font-range 0.2.1 → 1.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.
Files changed (45) hide show
  1. package/.eslintrc.json +12 -1
  2. package/.gitattributes +3 -0
  3. package/.vim/coc-settings.json +6 -0
  4. package/.yarn/plugins/@yarnpkg/plugin-outdated.cjs +35 -0
  5. package/.yarn/plugins/@yarnpkg/plugin-typescript.cjs +9 -0
  6. package/.yarn/sdks/eslint/bin/eslint.js +20 -0
  7. package/.yarn/sdks/eslint/lib/api.js +20 -0
  8. package/.yarn/sdks/eslint/package.json +6 -0
  9. package/.yarn/sdks/integrations.yml +6 -0
  10. package/.yarn/sdks/prettier/index.js +20 -0
  11. package/.yarn/sdks/prettier/package.json +6 -0
  12. package/.yarn/sdks/typescript/bin/tsc +20 -0
  13. package/.yarn/sdks/typescript/bin/tsserver +20 -0
  14. package/.yarn/sdks/typescript/lib/tsc.js +20 -0
  15. package/.yarn/sdks/typescript/lib/tsserver.js +223 -0
  16. package/.yarn/sdks/typescript/lib/tsserverlibrary.js +223 -0
  17. package/.yarn/sdks/typescript/lib/typescript.js +20 -0
  18. package/.yarn/sdks/typescript/package.json +6 -0
  19. package/README.md +141 -43
  20. package/__tests__/css_load.test.ts +52 -0
  21. package/__tests__/font/NotoSansKR-Local.css +3 -2
  22. package/__tests__/font/subset_glyphs.txt +1 -0
  23. package/__tests__/main.test.ts +241 -52
  24. package/__tests__/preset.test.ts +64 -0
  25. package/__tests__/shared.ts +25 -0
  26. package/build/main.d.ts +49 -0
  27. package/build/main.js +363 -0
  28. package/build/worker.d.ts +5 -0
  29. package/build/worker.js +10 -0
  30. package/jest.config.js +5 -5
  31. package/package.json +29 -26
  32. package/requirements.txt +4 -4
  33. package/src/main.ts +356 -106
  34. package/src/{types.ts → types.d.ts} +0 -2
  35. package/src/worker.ts +12 -0
  36. package/tsconfig.json +1 -0
  37. package/tsconfig.release.json +3 -2
  38. package/.github/workflows/nodejs.yml +0 -36
  39. package/.github/workflows/npm-publish.yml +0 -106
  40. package/build/src/main.d.ts +0 -18
  41. package/build/src/main.js +0 -199
  42. package/build/src/main.js.map +0 -1
  43. package/build/src/types.d.ts +0 -4
  44. package/build/src/types.js +0 -3
  45. package/build/src/types.js.map +0 -1
package/src/main.ts CHANGED
@@ -1,11 +1,33 @@
1
- import { join, parse } from 'path';
2
- import { createReadStream, createWriteStream, existsSync, mkdirSync } from 'fs';
3
- import fetch, { Headers } from 'node-fetch';
4
- import { parse as parseCSS, ParseOptions } from 'css-tree';
5
- import { execSync } from 'child_process';
6
- import { RequiredByValueExcept, ValueOf } from './types';
7
-
8
- // == Resouce Basics ==========================================================
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 ===========================================================
9
31
  export const targets = {
10
32
  weston: "https://fonts.googleapis.com/css2?family=Noto+Sans&display=swap",
11
33
  korean: "https://fonts.googleapis.com/css2?family=Noto+Sans+KR&display=swap",
@@ -41,7 +63,7 @@ function getCSSPath(dirPath: string, url: string) {
41
63
  }
42
64
 
43
65
  if (!existsSync(url)) {
44
- throw new Error(url + "Not vaild URL or PATH");
66
+ throw new Error("Not vaild URL or PATH: " + url);
45
67
  }
46
68
  return url;
47
69
  }
@@ -49,24 +71,31 @@ function getCSSPath(dirPath: string, url: string) {
49
71
  // == CSS I/O ==================================================================
50
72
  async function saveCSS(path: string, url: string) {
51
73
  // Fake header
74
+ const version = "109.0";
52
75
  const headers = new Headers({
53
76
  "Accept": "text/html,application/xhtml+xml,application/xml;",
54
- "User-Agent": "Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0"
77
+ "User-Agent": `Mozilla/5.0 (Windows NT 10.0; rv:${ version }) Gecko/20100101 Firefox/${ version }`
55
78
  });
56
79
 
57
80
  const res = await fetch(url, {
58
81
  method: "GET",
59
82
  headers: headers
60
83
  });
61
- const fileStream = createWriteStream(path);
84
+ if(res.status !== 200) {
85
+ throw new Error("Not vaild URL: " + url);
86
+ }
62
87
 
63
- await new Promise<void>((resolve, reject) => {
88
+ return new Promise<void>((resolve, reject) => {
89
+ const fileStream = createWriteStream(path);
64
90
  res.body.pipe(fileStream);
65
91
  res.body.on("error", (err) => {
66
- console.log('File write Error.');
92
+ console.log("File write Error.");
67
93
  reject(err);
68
94
  });
69
- fileStream.on("finish", function() {
95
+ res.body.on("close", () => {
96
+ fileStream.close();
97
+ });
98
+ fileStream.on("close", () => {
70
99
  resolve();
71
100
  });
72
101
  });
@@ -76,20 +105,19 @@ async function readCSS(path: string) {
76
105
  return new Promise<string>((resolve, reject) => {
77
106
  const readData: (string | Buffer)[] = [];
78
107
  createReadStream(path)
79
- .on('data', (data) => {
108
+ .on("data", (data) => {
80
109
  readData.push(data);
81
110
  })
82
- .on('end', async () => {
83
- await Promise.all(readData);
84
- const css = readData.join('');
111
+ .on("end", () => {
112
+ const css = readData.join("");
85
113
 
86
114
  resolve(css);
87
115
  })
88
- .on('error', reject);
116
+ .on("error", reject);
89
117
  });
90
118
  }
91
119
 
92
- // == CSS Parse ===============================================================
120
+ // == CSS Parse ================================================================
93
121
  const parseOptions: ParseOptions = {
94
122
  parseAtrulePrelude: false,
95
123
  parseRulePrelude: false,
@@ -99,134 +127,356 @@ const parseOptions: ParseOptions = {
99
127
  async function loadAST(dirPath: string, url = targets.korean, parseOption = parseOptions) {
100
128
  const cssPath = getCSSPath(dirPath, url);
101
129
  if (!existsSync(dirPath)) {
102
- mkdirSync(dirPath);
130
+ await mkdir(dirPath);
103
131
  }
104
132
  if (!existsSync(cssPath)) {
105
133
  await saveCSS(cssPath, url);
106
134
  }
107
135
 
108
136
  const css = await readCSS(cssPath);
109
- const ast = await parseCSS(css, parseOption);
110
- return ast;
111
- }
112
-
113
- function parseUnicodeRanges(parsed) {
114
- const fontFaceL = parsed.children;
115
- const uniRangeL = fontFaceL.map((faceValObj => {
116
- const faceBlockL = faceValObj.block.children;
117
- const uniRangeBlockL = faceBlockL.filter(faceBlock => faceBlock.property === "unicode-range");
118
- const uniRangeL = uniRangeBlockL.map(uniRangeBlock => uniRangeBlock.value.value);
119
- return uniRangeL.head.data;
120
- }));
121
-
122
- const uniRanges: string[] = [];
123
- uniRangeL.forEach(unicodeRange => {
124
- uniRanges.push(unicodeRange);
125
- });
126
- return uniRanges;
137
+ return cssAST(css, parseOption);
127
138
  }
128
139
 
129
- export async function getUnicodeRanges(dirPath = "src", url = targets.korean): Promise<string[]> {
130
- const ast = await loadAST(dirPath, url);
131
- return parseUnicodeRanges(ast);
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;
132
173
  }
133
174
 
134
- // == Options =================================================================
135
- interface fontRangeOptionI {
136
- savePath: string;
137
- format: string;
175
+ // == Options - Basics =========================================================
176
+ export interface FontDefaultOptionI {
177
+ saveDir: string;
178
+ format: Format;
138
179
  nameFormat: string;
139
- defaultArgs: string;
140
- etcArgs: string;
180
+ logFormat: string;
181
+ defaultArgs: string[];
182
+ etcArgs: string[];
141
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";
142
200
 
143
- function getDefaultOptions(): RequiredByValueExcept<fontRangeOptionI, 'savePath'> {
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"> {
144
216
  return {
145
217
  format: "woff2",
146
218
  nameFormat: "{NAME}_{INDEX}{EXT}",
147
- defaultArgs: "--layout-features='*' \
148
- --glyph-names \
149
- --symbol-cmap \
150
- --legacy-cmap \
151
- --notdef-glyph \
152
- --notdef-outline \
153
- --recommended-glyphs \
154
- --name-legacy \
155
- --drop-tables= \
156
- --name-IDs='*' \
157
- --name-languages='*'",
158
- etcArgs: ""
219
+ logFormat: "Convert {ORIGIN} -> {OUTPUT}",
220
+ defaultArgs: defaultArgs,
221
+ etcArgs: []
159
222
  };
160
223
  }
161
224
 
162
- function getOption(options: Partial<fontRangeOptionI>, key: keyof fontRangeOptionI, alterValue: ValueOf<fontRangeOptionI>) {
163
- return Object.prototype.hasOwnProperty.call(options, key)
164
- ? options[key]
165
- : alterValue;
166
- }
167
-
168
- function getName(nameFormat: string, fontName: string, index: number, fontExt: string) {
169
- return nameFormat
170
- .replace( "{NAME}", fontName)
171
- .replace("{INDEX}", index.toString())
172
- .replace( "{EXT}", fontExt);
173
- }
174
-
175
- // == Main ====================================================================
176
- function getFormat(format: string) {
225
+ // == Options - Get Info =======================================================
226
+ function getFormat(format: Format) {
177
227
  switch(format) {
178
228
  case "otf": return "otf";
179
229
  case "ttf": return "ttf";
180
230
  case "woff2": return "woff2";
181
231
  case "woff": return "woff";
182
232
  case "woff-zopfli": return "woff";
183
- default: return "woff2";
184
233
  }
185
234
  }
186
235
 
187
- function formatOption(format: string, ext = true) {
236
+ function formatOption(format: Format) {
188
237
  const formatName = getFormat(format);
189
- if(ext) return "." + formatName;
190
238
 
191
- if(format === "otf" || format === "ttf") return "";
192
- return "--flavor='" + ((format === "woff-zopfli")
193
- ? formatName + "' --with-zopfli "
194
- : formatName + "' ");
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);
195
265
  }
196
266
 
197
- export function fontRange(
198
- url = targets.korean, fontPath = "",
199
- fontRangeOption?: fontRangeOptionI['savePath'] | Partial<fontRangeOptionI>
200
- ): Promise<Buffer[]> {
201
- const options = Object.assign(
267
+ function getOptionInfos(fontPath = "", fontOption?: ArgOptionsT, indexIndicate = "") {
268
+ const options: FontPipeOptionT = Object.assign(
269
+ { fromCSS: "default" } satisfies Partial<FontRangeOptionI>,
202
270
  getDefaultOptions(),
203
- typeof(fontRangeOption) === 'string'
204
- ? { savePath: fontRangeOption }
205
- : fontRangeOption
271
+ typeof(fontOption) === "string"
272
+ ? { saveDir: fontOption }
273
+ : fontOption
206
274
  );
207
275
 
208
276
  const format = options.format;
209
277
  const pathInfo = parse(fontPath);
210
278
  const fontDir = pathInfo.dir;
279
+ const fontBase = pathInfo.base;
211
280
  const fontName = pathInfo.name;
212
- const fontExt = formatOption(format);
281
+ const fontExt = "." + getFormat(format);
213
282
 
214
- const dirPath = getOption(options, 'savePath', fontDir);
215
- const ranges = getUnicodeRanges(dirPath, url);
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);
216
290
 
217
- const convertOption = formatOption(format, false);
291
+ const convertOption = formatOption(format);
218
292
  const defaultOption = options.defaultArgs;
219
293
  const etcOption = options.etcArgs;
294
+ const baseOption = [
295
+ ...convertOption,
296
+ ...defaultOption,
297
+ ...etcOption
298
+ ].filter(option => option !== "");
220
299
 
221
- const nameFormat = options.nameFormat;
222
- return ranges.then(eachRanges => eachRanges.map((unicodes, i) => {
223
- const saveOption = "--output-file='" +
224
- join(dirPath, getName(nameFormat, fontName, i, fontExt)) + "' ";
225
- const unicodeRanges = unicodes.split(', ').join(',');
226
- const unicodeOption = "--unicodes='" + unicodeRanges + "' ";
227
-
228
- const options = " '" + fontPath + "' " + saveOption + unicodeOption
229
- + convertOption + defaultOption + etcOption;
230
- return execSync("pyftsubset" + options);
231
- }));
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);
232
482
  }
@@ -1,5 +1,3 @@
1
1
  // https://stackoverflow.com/questions/52703321/make-some-properties-optional-in-a-typescript-type
2
2
  type Diff<T, U> = T extends U ? never : T;
3
3
  export type RequiredByValueExcept<T, TOptional extends keyof T> = Pick<T, Diff<keyof T, TOptional>> & Partial<T>;
4
-
5
- export type ValueOf<T> = T[keyof T];
package/src/worker.ts ADDED
@@ -0,0 +1,12 @@
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 CHANGED
@@ -6,6 +6,7 @@
6
6
  ],
7
7
  "module": "commonjs",
8
8
  "moduleResolution": "node",
9
+ "esModuleInterop": true,
9
10
  "allowSyntheticDefaultImports": true,
10
11
  "allowJs": true,
11
12
  "importHelpers": true,
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "extends": "./tsconfig.json",
3
3
  "compilerOptions": {
4
- "rootDir": ".",
4
+ "rootDir": "src",
5
5
  "outDir": "build",
6
6
  "removeComments": true,
7
- "declaration": true
7
+ "declaration": true,
8
+ "sourceMap": false
8
9
  },
9
10
  "include": [
10
11
  "src/**/*"
@@ -1,36 +0,0 @@
1
- name: Node.js CI
2
-
3
- on: [push, pull_request]
4
-
5
- jobs:
6
- build:
7
- runs-on: ubuntu-latest
8
- steps:
9
- - uses: actions/checkout@v2
10
- - uses: volta-cli/action@v1
11
- - name: pip cache
12
- id: pip-cache
13
- uses: actions/cache@v2
14
- with:
15
- path: ~/.cache/pip
16
- key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
17
- restore-keys: |
18
- ${{ runner.os }}-pip-
19
- - name: node cache
20
- id: node-cache
21
- uses: actions/cache@v2
22
- with:
23
- path: node_modules
24
- key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
25
- restore-keys: |
26
- ${{ runner.os }}-node-
27
- - run: pip install -r ./requirements.txt
28
- - name: npm install
29
- if: steps.node-cache.outputs.cache-hit != 'true'
30
- run: npm install
31
- - run: npm ci --no-audit
32
- - run: npm run lint --if-present
33
- - run: npm test
34
- - run: npm run build --if-present
35
- env:
36
- CI: true