font-range 1.0.1 → 1.0.3
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/README.md +5 -5
- package/build/main.js +74 -22
- package/package.json +19 -16
- package/.editorconfig +0 -15
- package/.eslintignore +0 -2
- package/.eslintrc.json +0 -35
- package/.gitattributes +0 -3
- package/.prettierrc +0 -12
- package/.travis.yml +0 -22
- package/.vim/coc-settings.json +0 -6
- package/.yarn/plugins/@yarnpkg/plugin-outdated.cjs +0 -35
- package/.yarn/plugins/@yarnpkg/plugin-typescript.cjs +0 -9
- package/.yarn/sdks/eslint/bin/eslint.js +0 -20
- package/.yarn/sdks/eslint/lib/api.js +0 -20
- package/.yarn/sdks/eslint/package.json +0 -6
- package/.yarn/sdks/integrations.yml +0 -6
- package/.yarn/sdks/prettier/index.js +0 -20
- package/.yarn/sdks/prettier/package.json +0 -6
- package/.yarn/sdks/typescript/bin/tsc +0 -20
- package/.yarn/sdks/typescript/bin/tsserver +0 -20
- package/.yarn/sdks/typescript/lib/tsc.js +0 -20
- package/.yarn/sdks/typescript/lib/tsserver.js +0 -223
- package/.yarn/sdks/typescript/lib/tsserverlibrary.js +0 -223
- package/.yarn/sdks/typescript/lib/typescript.js +0 -20
- package/.yarn/sdks/typescript/package.json +0 -6
- package/__tests__/css_load.test.ts +0 -52
- package/__tests__/font/NotoSansKR-Local.css +0 -1081
- package/__tests__/font/NotoSansKR-Regular.otf +0 -0
- package/__tests__/font/OFL.txt +0 -91
- package/__tests__/font/subset_glyphs.txt +0 -1
- package/__tests__/main.test.ts +0 -267
- package/__tests__/preset.test.ts +0 -64
- package/__tests__/shared.ts +0 -25
- package/jest.config.js +0 -22
- package/requirements.txt +0 -10
- package/resource/Korean_0.png +0 -0
- package/resource/Korean_1.png +0 -0
- package/resource/Korean_Japanese.png +0 -0
- package/resource/News_Chinese.gif +0 -0
- package/resource/News_Japanese.gif +0 -0
- package/resource/News_Japanese.png +0 -0
- package/resource/News_Korean.gif +0 -0
- package/resource/Noto_0.png +0 -0
- package/resource/Noto_1.png +0 -0
- package/src/main.ts +0 -482
- package/src/types.d.ts +0 -3
- package/src/worker.ts +0 -12
- package/tsconfig.json +0 -32
- package/tsconfig.release.json +0 -13
package/src/main.ts
DELETED
|
@@ -1,482 +0,0 @@
|
|
|
1
|
-
import { join, parse } from "path";
|
|
2
|
-
import { createReadStream, createWriteStream, existsSync } from "fs";
|
|
3
|
-
import { mkdir } from "fs/promises";
|
|
4
|
-
|
|
5
|
-
import Piscina from "piscina";
|
|
6
|
-
import fetch, { Headers } from "@esm2cjs/node-fetch";
|
|
7
|
-
import { parse as cssAST, ParseOptions, walk } from "css-tree";
|
|
8
|
-
import type { Declaration } from "css-tree";
|
|
9
|
-
|
|
10
|
-
import type WorkerFn from "./worker";
|
|
11
|
-
import type { RequiredByValueExcept } from "./types";
|
|
12
|
-
|
|
13
|
-
// == Worker ===================================================================
|
|
14
|
-
type WorkerRT = ReturnType<typeof WorkerFn>;
|
|
15
|
-
|
|
16
|
-
class Worker {
|
|
17
|
-
private static instance: Piscina;
|
|
18
|
-
private constructor() { }
|
|
19
|
-
|
|
20
|
-
public static getInstance(): Piscina {
|
|
21
|
-
if(!Worker.instance) {
|
|
22
|
-
Worker.instance = new Piscina({
|
|
23
|
-
filename: join(__dirname, "../", "build", "worker.js")
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
return Worker.instance;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// == Resouce Basics ===========================================================
|
|
31
|
-
export const targets = {
|
|
32
|
-
weston: "https://fonts.googleapis.com/css2?family=Noto+Sans&display=swap",
|
|
33
|
-
korean: "https://fonts.googleapis.com/css2?family=Noto+Sans+KR&display=swap",
|
|
34
|
-
japanese: "https://fonts.googleapis.com/css2?family=Noto+Sans+JP&display=swap",
|
|
35
|
-
chinese: "https://fonts.googleapis.com/css2?family=Noto+Sans+SC&display=swap",
|
|
36
|
-
chinese_traditional: "https://fonts.googleapis.com/css2?family=Noto+Sans+TC&display=swap",
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
function getFontName(url: string) {
|
|
40
|
-
const encodedURL = decodeURI(url);
|
|
41
|
-
const urlObj = new URL(encodedURL);
|
|
42
|
-
const urlParams = urlObj.searchParams;
|
|
43
|
-
const fontName = urlParams.get("family");
|
|
44
|
-
return fontName;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
// https://stackoverflow.com/questions/5717093/check-if-a-javascript-string-is-a-url
|
|
48
|
-
function validURL(str: string) {
|
|
49
|
-
const pattern = new RegExp("^(https?:\\/\\/)?"+ // protocol
|
|
50
|
-
"((([a-z\\d]([a-z\\d-]*[a-z\\d])*)\\.)+[a-z]{2,}|"+ // domain name
|
|
51
|
-
"((\\d{1,3}\\.){3}\\d{1,3}))"+ // OR ip (v4) address
|
|
52
|
-
"(\\:\\d+)?(\\/[-a-z\\d%_.~+]*)*"+ // port and path
|
|
53
|
-
"(\\?[;&a-z\\d%_.~+=-]*)?"+ // query string
|
|
54
|
-
"(\\#[-a-z\\d_]*)?$","i"); // fragment locator
|
|
55
|
-
return !!pattern.test(str);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
function getCSSPath(dirPath: string, url: string) {
|
|
59
|
-
if (validURL(url)) {
|
|
60
|
-
const fontName = getFontName(url);
|
|
61
|
-
const cssPath = join(dirPath, fontName + ".css");
|
|
62
|
-
return cssPath;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
if (!existsSync(url)) {
|
|
66
|
-
throw new Error("Not vaild URL or PATH: " + url);
|
|
67
|
-
}
|
|
68
|
-
return url;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// == CSS I/O ==================================================================
|
|
72
|
-
async function saveCSS(path: string, url: string) {
|
|
73
|
-
// Fake header
|
|
74
|
-
const version = "109.0";
|
|
75
|
-
const headers = new Headers({
|
|
76
|
-
"Accept": "text/html,application/xhtml+xml,application/xml;",
|
|
77
|
-
"User-Agent": `Mozilla/5.0 (Windows NT 10.0; rv:${ version }) Gecko/20100101 Firefox/${ version }`
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
const res = await fetch(url, {
|
|
81
|
-
method: "GET",
|
|
82
|
-
headers: headers
|
|
83
|
-
});
|
|
84
|
-
if(res.status !== 200) {
|
|
85
|
-
throw new Error("Not vaild URL: " + url);
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
return new Promise<void>((resolve, reject) => {
|
|
89
|
-
const fileStream = createWriteStream(path);
|
|
90
|
-
res.body.pipe(fileStream);
|
|
91
|
-
res.body.on("error", (err) => {
|
|
92
|
-
console.log("File write Error.");
|
|
93
|
-
reject(err);
|
|
94
|
-
});
|
|
95
|
-
res.body.on("close", () => {
|
|
96
|
-
fileStream.close();
|
|
97
|
-
});
|
|
98
|
-
fileStream.on("close", () => {
|
|
99
|
-
resolve();
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
async function readCSS(path: string) {
|
|
105
|
-
return new Promise<string>((resolve, reject) => {
|
|
106
|
-
const readData: (string | Buffer)[] = [];
|
|
107
|
-
createReadStream(path)
|
|
108
|
-
.on("data", (data) => {
|
|
109
|
-
readData.push(data);
|
|
110
|
-
})
|
|
111
|
-
.on("end", () => {
|
|
112
|
-
const css = readData.join("");
|
|
113
|
-
|
|
114
|
-
resolve(css);
|
|
115
|
-
})
|
|
116
|
-
.on("error", reject);
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
// == CSS Parse ================================================================
|
|
121
|
-
const parseOptions: ParseOptions = {
|
|
122
|
-
parseAtrulePrelude: false,
|
|
123
|
-
parseRulePrelude: false,
|
|
124
|
-
parseValue: false
|
|
125
|
-
};
|
|
126
|
-
|
|
127
|
-
async function loadAST(dirPath: string, url = targets.korean, parseOption = parseOptions) {
|
|
128
|
-
const cssPath = getCSSPath(dirPath, url);
|
|
129
|
-
if (!existsSync(dirPath)) {
|
|
130
|
-
await mkdir(dirPath);
|
|
131
|
-
}
|
|
132
|
-
if (!existsSync(cssPath)) {
|
|
133
|
-
await saveCSS(cssPath, url);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
const css = await readCSS(cssPath);
|
|
137
|
-
return cssAST(css, parseOption);
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
interface BlockI {
|
|
141
|
-
src: string;
|
|
142
|
-
unicodes: string;
|
|
143
|
-
}
|
|
144
|
-
function setBlock(block: BlockI, elem: Declaration, blockProp: keyof BlockI, elemProp: string) {
|
|
145
|
-
if(elem.property === elemProp) {
|
|
146
|
-
if(elem.value.type === "Raw") {
|
|
147
|
-
block[blockProp] = elem.value.value;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
export async function parseCSS(dirPath = "src", url = targets.korean) {
|
|
153
|
-
const ast = await loadAST(dirPath, url);
|
|
154
|
-
const parsed = [] as BlockI[];
|
|
155
|
-
|
|
156
|
-
walk(ast, { visit: "Atrule", enter(node) {
|
|
157
|
-
if(node.name === "font-face") {
|
|
158
|
-
const block = {
|
|
159
|
-
src: "",
|
|
160
|
-
unicodes: ""
|
|
161
|
-
};
|
|
162
|
-
walk(node, { visit: "Declaration", enter(elem) {
|
|
163
|
-
setBlock(block, elem, "src", "src");
|
|
164
|
-
setBlock(block, elem, "unicodes", "unicode-range");
|
|
165
|
-
}});
|
|
166
|
-
|
|
167
|
-
if(block.src !== "" || block.unicodes !== "") {
|
|
168
|
-
parsed.push(block);
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}});
|
|
172
|
-
return parsed;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
// == Options - Basics =========================================================
|
|
176
|
-
export interface FontDefaultOptionI {
|
|
177
|
-
saveDir: string;
|
|
178
|
-
format: Format;
|
|
179
|
-
nameFormat: string;
|
|
180
|
-
logFormat: string;
|
|
181
|
-
defaultArgs: string[];
|
|
182
|
-
etcArgs: string[];
|
|
183
|
-
}
|
|
184
|
-
export interface FontRangeOptionI extends FontDefaultOptionI {
|
|
185
|
-
fromCSS: "default" | "srcIndex" | "srcName";
|
|
186
|
-
}
|
|
187
|
-
export interface FontSubsetOptionI extends FontDefaultOptionI {
|
|
188
|
-
textFile: string;
|
|
189
|
-
text: string;
|
|
190
|
-
}
|
|
191
|
-
export interface FontPipeOptionI extends FontRangeOptionI, FontSubsetOptionI {
|
|
192
|
-
cssFile: string;
|
|
193
|
-
}
|
|
194
|
-
type ArgOptionT<I> = FontDefaultOptionI["saveDir"] | Partial<I>;
|
|
195
|
-
type FontRangeOptionT = ArgOptionT<FontRangeOptionI>;
|
|
196
|
-
type FontSubsetOptionT = ArgOptionT<FontSubsetOptionI>;
|
|
197
|
-
type FontPipeOptionT = Partial<FontPipeOptionI>;
|
|
198
|
-
type ArgOptionsT = FontRangeOptionT | FontSubsetOptionT | FontPipeOptionT;
|
|
199
|
-
type Format = "otf" | "ttf" | "woff2" | "woff" | "woff-zopfli";
|
|
200
|
-
|
|
201
|
-
export const defaultArgs = [
|
|
202
|
-
"--layout-features=*",
|
|
203
|
-
"--glyph-names",
|
|
204
|
-
"--symbol-cmap",
|
|
205
|
-
"--legacy-cmap",
|
|
206
|
-
"--notdef-glyph",
|
|
207
|
-
"--notdef-outline",
|
|
208
|
-
"--recommended-glyphs",
|
|
209
|
-
"--name-legacy",
|
|
210
|
-
"--drop-tables=",
|
|
211
|
-
"--name-IDs=*",
|
|
212
|
-
"--name-languages=*"
|
|
213
|
-
];
|
|
214
|
-
|
|
215
|
-
function getDefaultOptions(): RequiredByValueExcept<FontDefaultOptionI, "saveDir"> {
|
|
216
|
-
return {
|
|
217
|
-
format: "woff2",
|
|
218
|
-
nameFormat: "{NAME}_{INDEX}{EXT}",
|
|
219
|
-
logFormat: "Convert {ORIGIN} -> {OUTPUT}",
|
|
220
|
-
defaultArgs: defaultArgs,
|
|
221
|
-
etcArgs: []
|
|
222
|
-
};
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
// == Options - Get Info =======================================================
|
|
226
|
-
function getFormat(format: Format) {
|
|
227
|
-
switch(format) {
|
|
228
|
-
case "otf": return "otf";
|
|
229
|
-
case "ttf": return "ttf";
|
|
230
|
-
case "woff2": return "woff2";
|
|
231
|
-
case "woff": return "woff";
|
|
232
|
-
case "woff-zopfli": return "woff";
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
function formatOption(format: Format) {
|
|
237
|
-
const formatName = getFormat(format);
|
|
238
|
-
|
|
239
|
-
if(format === "otf" || format === "ttf") return [""];
|
|
240
|
-
return [
|
|
241
|
-
"--flavor=" + formatName,
|
|
242
|
-
(format === "woff-zopfli") ? "--with-zopfli" : ""
|
|
243
|
-
];
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
function fileNameInit(nameFormat: string, fontName: string, fontExt: string) {
|
|
247
|
-
return nameFormat
|
|
248
|
-
.replace( "{NAME}", fontName)
|
|
249
|
-
.replace( "{EXT}", fontExt );
|
|
250
|
-
}
|
|
251
|
-
function getFileName(initName: string, index?: number | string) {
|
|
252
|
-
return initName
|
|
253
|
-
.replace("{INDEX}",
|
|
254
|
-
(typeof index === "number")
|
|
255
|
-
? index.toString()
|
|
256
|
-
: (typeof index === "string")
|
|
257
|
-
? index
|
|
258
|
-
: ""
|
|
259
|
-
);
|
|
260
|
-
}
|
|
261
|
-
function getConsoleLog(logFormat: string, origin: string, output: string) {
|
|
262
|
-
return logFormat
|
|
263
|
-
.replace("{ORIGIN}", origin)
|
|
264
|
-
.replace("{OUTPUT}", output);
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
function getOptionInfos(fontPath = "", fontOption?: ArgOptionsT, indexIndicate = "") {
|
|
268
|
-
const options: FontPipeOptionT = Object.assign(
|
|
269
|
-
{ fromCSS: "default" } satisfies Partial<FontRangeOptionI>,
|
|
270
|
-
getDefaultOptions(),
|
|
271
|
-
typeof(fontOption) === "string"
|
|
272
|
-
? { saveDir: fontOption }
|
|
273
|
-
: fontOption
|
|
274
|
-
);
|
|
275
|
-
|
|
276
|
-
const format = options.format;
|
|
277
|
-
const pathInfo = parse(fontPath);
|
|
278
|
-
const fontDir = pathInfo.dir;
|
|
279
|
-
const fontBase = pathInfo.base;
|
|
280
|
-
const fontName = pathInfo.name;
|
|
281
|
-
const fontExt = "." + getFormat(format);
|
|
282
|
-
|
|
283
|
-
const dirPath = Object.prototype.hasOwnProperty.call(options, "saveDir") ? options["saveDir"] : fontDir;
|
|
284
|
-
const nameFormat = options.nameFormat;
|
|
285
|
-
const logFormat = options.logFormat;
|
|
286
|
-
|
|
287
|
-
const initName = fileNameInit(nameFormat, fontName, fontExt);
|
|
288
|
-
const output = getFileName(initName, indexIndicate);
|
|
289
|
-
const logMsg = getConsoleLog(logFormat, fontBase, output);
|
|
290
|
-
|
|
291
|
-
const convertOption = formatOption(format);
|
|
292
|
-
const defaultOption = options.defaultArgs;
|
|
293
|
-
const etcOption = options.etcArgs;
|
|
294
|
-
const baseOption = [
|
|
295
|
-
...convertOption,
|
|
296
|
-
...defaultOption,
|
|
297
|
-
...etcOption
|
|
298
|
-
].filter(option => option !== "");
|
|
299
|
-
|
|
300
|
-
const worker = Worker.getInstance();
|
|
301
|
-
|
|
302
|
-
return {
|
|
303
|
-
dirPath,
|
|
304
|
-
initName,
|
|
305
|
-
logMsg,
|
|
306
|
-
|
|
307
|
-
baseOption,
|
|
308
|
-
worker,
|
|
309
|
-
|
|
310
|
-
fromCSS: options.fromCSS
|
|
311
|
-
};
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
// == Options - Others =========================================================
|
|
315
|
-
function getSrcInfo(src: string) {
|
|
316
|
-
const first = src.split(",").find((str) => {
|
|
317
|
-
return str.indexOf("url(") === 0;
|
|
318
|
-
});
|
|
319
|
-
if(typeof first === "undefined") return {
|
|
320
|
-
base: "",
|
|
321
|
-
index: 0
|
|
322
|
-
};
|
|
323
|
-
|
|
324
|
-
const reStr = "url\\(";
|
|
325
|
-
const reMdl = "(.+?)";
|
|
326
|
-
const reEnd = "\\)";
|
|
327
|
-
const quote = "(\\\\?['\"])?";
|
|
328
|
-
const regex = new RegExp(
|
|
329
|
-
reStr + quote + reMdl + quote + reEnd
|
|
330
|
-
);
|
|
331
|
-
|
|
332
|
-
const urlContent = first.match(regex)[2];
|
|
333
|
-
const parsedURL = parse(urlContent);
|
|
334
|
-
return {
|
|
335
|
-
base: parsedURL.base,
|
|
336
|
-
index: parseInt(
|
|
337
|
-
parsedURL.name.split(".").pop() // google font index at latest
|
|
338
|
-
)
|
|
339
|
-
};
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
function getSaveOption(dirPath: string, initName: string, index?: number) {
|
|
343
|
-
const fileName = getFileName(initName, index);
|
|
344
|
-
return ("--output-file=" + join(dirPath, fileName));
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
function getSubsetOption(fontSubsetOption?: FontSubsetOptionT) {
|
|
348
|
-
if(
|
|
349
|
-
typeof fontSubsetOption !== "undefined" &&
|
|
350
|
-
typeof fontSubsetOption !== "string"
|
|
351
|
-
) {
|
|
352
|
-
if("textFile" in fontSubsetOption) {
|
|
353
|
-
return ("--text-file=" + fontSubsetOption.textFile);
|
|
354
|
-
}
|
|
355
|
-
if("text" in fontSubsetOption) {
|
|
356
|
-
return ("--text=" + fontSubsetOption.text );
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
return "--glyphs=*";
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
// == Main =====================================================================
|
|
363
|
-
export async function fontRange(fontPath = "", url = targets.korean, fontRangeOption?: FontRangeOptionT) {
|
|
364
|
-
const {
|
|
365
|
-
dirPath,
|
|
366
|
-
initName,
|
|
367
|
-
logMsg,
|
|
368
|
-
|
|
369
|
-
baseOption,
|
|
370
|
-
worker,
|
|
371
|
-
|
|
372
|
-
fromCSS
|
|
373
|
-
} = getOptionInfos(fontPath, fontRangeOption, "n");
|
|
374
|
-
|
|
375
|
-
const ranges = await parseCSS(dirPath, url);
|
|
376
|
-
const result = ranges.map(async ({src, unicodes}, i) => {
|
|
377
|
-
const srcInfo = getSrcInfo(src);
|
|
378
|
-
const saveOption = getSaveOption(
|
|
379
|
-
dirPath,
|
|
380
|
-
(fromCSS === "srcName" && srcInfo.base !== "")
|
|
381
|
-
? srcInfo.base
|
|
382
|
-
: initName,
|
|
383
|
-
(fromCSS === "srcIndex" && srcInfo.base !== "")
|
|
384
|
-
? srcInfo.index
|
|
385
|
-
: i
|
|
386
|
-
);
|
|
387
|
-
const unicodeRanges = unicodes.split(", ").join(",");
|
|
388
|
-
const unicodeOption = "--unicodes=" + unicodeRanges;
|
|
389
|
-
|
|
390
|
-
const options = [fontPath, saveOption, unicodeOption, ...baseOption];
|
|
391
|
-
const logInfo = (i === 0) ? logMsg : "";
|
|
392
|
-
const result: WorkerRT = await worker.run({ options, log: logInfo});
|
|
393
|
-
return result;
|
|
394
|
-
});
|
|
395
|
-
|
|
396
|
-
return await Promise.all(result);
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
export async function fontSubset(fontPath = "", fontSubsetOption?: FontSubsetOptionT) {
|
|
400
|
-
const {
|
|
401
|
-
dirPath,
|
|
402
|
-
initName,
|
|
403
|
-
logMsg,
|
|
404
|
-
|
|
405
|
-
baseOption,
|
|
406
|
-
worker
|
|
407
|
-
} = getOptionInfos(fontPath, fontSubsetOption);
|
|
408
|
-
if(!existsSync(dirPath)) await mkdir(dirPath);
|
|
409
|
-
|
|
410
|
-
const subsetOption = getSubsetOption(fontSubsetOption);
|
|
411
|
-
const saveOption = getSaveOption(dirPath, initName);
|
|
412
|
-
|
|
413
|
-
const options = [fontPath, saveOption, subsetOption, ...baseOption];
|
|
414
|
-
const result: WorkerRT = await worker.run({ options, log: logMsg});
|
|
415
|
-
return result;
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
// == Pipeline =================================================================
|
|
419
|
-
export interface FontPipeI {
|
|
420
|
-
fontPath: string;
|
|
421
|
-
option?: FontPipeOptionT;
|
|
422
|
-
}
|
|
423
|
-
function fontPipeExec(subsetTarget: FontPipeI) {
|
|
424
|
-
const { fontPath, option } = subsetTarget;
|
|
425
|
-
|
|
426
|
-
return ((typeof option !== "undefined") &&
|
|
427
|
-
(typeof option.cssFile !== "undefined"))
|
|
428
|
-
? fontRange(fontPath, option.cssFile, option)
|
|
429
|
-
: fontSubset(fontPath, option);
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
function shardNum(shardStr: string, content: string) {
|
|
433
|
-
const num = Math.abs(parseInt(shardStr, 10));
|
|
434
|
-
|
|
435
|
-
if(isNaN(num) || num <= 0) {
|
|
436
|
-
throw new Error("<" + content + "> must be a positive number");
|
|
437
|
-
}
|
|
438
|
-
return num;
|
|
439
|
-
}
|
|
440
|
-
function getShardInfo(shardEnv: string) {
|
|
441
|
-
const [indexStr, totalStr] = shardEnv.split("/");
|
|
442
|
-
const index = shardNum(indexStr, "index");
|
|
443
|
-
const total = shardNum(totalStr, "total");
|
|
444
|
-
|
|
445
|
-
if(index > total) {
|
|
446
|
-
throw new Error("<index> must be less then <total>")
|
|
447
|
-
}
|
|
448
|
-
return [index, total] as const;
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
interface ShardI {
|
|
452
|
-
shard: string;
|
|
453
|
-
shardFormat: string;
|
|
454
|
-
}
|
|
455
|
-
type ShardT = ShardI["shard"] | Partial<ShardI>
|
|
456
|
-
export async function fontPipe(subsetList: FontPipeI[], shard?: ShardT) {
|
|
457
|
-
const shardEnv = (typeof shard === "object" && typeof shard.shard === "string")
|
|
458
|
-
? shard.shard
|
|
459
|
-
: (typeof shard === "object" || typeof shard === "undefined")
|
|
460
|
-
? process.env.SHARD || "1/1"
|
|
461
|
-
: shard;
|
|
462
|
-
const shardFormat = (typeof shard === "object" && typeof shard.shardFormat === "string")
|
|
463
|
-
? shard.shardFormat
|
|
464
|
-
: "== {START}/{END} ==========";
|
|
465
|
-
|
|
466
|
-
const [index, total] = getShardInfo(shardEnv);
|
|
467
|
-
const shardSize = Math.ceil(subsetList.length / total);
|
|
468
|
-
const shardStart = shardSize * (index - 1);
|
|
469
|
-
const shardEnd = shardSize * index;
|
|
470
|
-
|
|
471
|
-
if(shardEnv !== "1/1") {
|
|
472
|
-
const shardMsg = shardFormat
|
|
473
|
-
.replace("{START}", index.toString())
|
|
474
|
-
.replace("{END}", total.toString());
|
|
475
|
-
console.log(shardMsg);
|
|
476
|
-
}
|
|
477
|
-
|
|
478
|
-
const result = subsetList
|
|
479
|
-
.slice(shardStart, shardEnd)
|
|
480
|
-
.map(fontPipeExec);
|
|
481
|
-
return await Promise.all(result);
|
|
482
|
-
}
|
package/src/types.d.ts
DELETED
package/src/worker.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { execaSync } from "@esm2cjs/execa";
|
|
2
|
-
|
|
3
|
-
export interface SubsetI {
|
|
4
|
-
options: string[],
|
|
5
|
-
log?: string
|
|
6
|
-
}
|
|
7
|
-
export default function subset({options, log = ""}: SubsetI) {
|
|
8
|
-
if(log !== "") {
|
|
9
|
-
console.log(log);
|
|
10
|
-
}
|
|
11
|
-
return execaSync("pyftsubset", options);
|
|
12
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "es6",
|
|
4
|
-
"lib": [
|
|
5
|
-
"esnext", "dom", "dom.iterable", "scripthost"
|
|
6
|
-
],
|
|
7
|
-
"module": "commonjs",
|
|
8
|
-
"moduleResolution": "node",
|
|
9
|
-
"esModuleInterop": true,
|
|
10
|
-
"allowSyntheticDefaultImports": true,
|
|
11
|
-
"allowJs": true,
|
|
12
|
-
"importHelpers": true,
|
|
13
|
-
"jsx": "react",
|
|
14
|
-
"alwaysStrict": true,
|
|
15
|
-
"sourceMap": true,
|
|
16
|
-
"forceConsistentCasingInFileNames": true,
|
|
17
|
-
"noFallthroughCasesInSwitch": true,
|
|
18
|
-
"noImplicitReturns": true,
|
|
19
|
-
"noUnusedLocals": true,
|
|
20
|
-
"noUnusedParameters": true,
|
|
21
|
-
"noImplicitAny": false,
|
|
22
|
-
"noImplicitThis": false,
|
|
23
|
-
"strictNullChecks": false
|
|
24
|
-
},
|
|
25
|
-
"include": [
|
|
26
|
-
"src/**/*",
|
|
27
|
-
"__tests__/**/*"
|
|
28
|
-
],
|
|
29
|
-
"exclude": [
|
|
30
|
-
"build/**/*"
|
|
31
|
-
]
|
|
32
|
-
}
|