@fastkit/icon-font-gen 0.16.2 → 0.16.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/dist/cli.mjs CHANGED
@@ -1,10 +1,7 @@
1
- import { c as IconFontGenError, i as generate, l as DEFAULT_CONFIG_FILENAME, u as DEFAULT_DEST_DIRNAME } from "./generator-BzNGBKOM.mjs";
1
+ import { d as DEFAULT_CONFIG_FILENAME, f as DEFAULT_DEST_DIRNAME, i as generate, l as version, u as IconFontGenError } from "./generator-bCFFCSuU.mjs";
2
2
  import path from "node:path";
3
3
  import { esbuildRequire, findPackageDir } from "@fastkit/node-util";
4
4
  import { cac } from "cac";
5
- //#region package.json
6
- var version = "0.16.2";
7
- //#endregion
8
5
  //#region src/cli.ts
9
6
  async function cli() {
10
7
  const _cli = cac("icon-font");
package/dist/cli.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.mjs","names":["pkg.version"],"sources":["../package.json","../src/cli.ts"],"sourcesContent":["","import { cac } from 'cac';\nimport path from 'node:path';\nimport { findPackageDir, esbuildRequire } from '@fastkit/node-util';\nimport {\n DEFAULT_DEST_DIRNAME,\n DEFAULT_CONFIG_FILENAME,\n IconFontConfig,\n} from './schemes';\nimport { generate } from './generator';\nimport { IconFontGenError } from './logger';\nimport pkg from '../package.json';\n\nexport async function cli() {\n const _cli = cac('icon-font');\n\n _cli\n .option('-d, --dest <string>', 'Destination for generated fonts.', {\n default: path.join(process.cwd(), `${DEFAULT_DEST_DIRNAME}`),\n })\n .command(\n '[config file path]',\n `\nPath of the configuration file. (default: [your package directory]${path.sep}${DEFAULT_CONFIG_FILENAME})\n You must export default <IconFontConfig>.\n\n e.g.\n \\`\\`\\`\n import { createIconFontConfig } from '@fastkit/icon-font-gen';\n\n export default createIconFontConfig({ ... });\n \\`\\`\\`\n `.trim(),\n )\n .action(\n async (configPath: string | undefined, options: { dest: string }) => {\n if (!configPath) {\n const pkgDir = await findPackageDir();\n if (!pkgDir) {\n throw new IconFontGenError('missing package directory.');\n }\n configPath = path.join(pkgDir, DEFAULT_CONFIG_FILENAME);\n }\n\n const dest = path.resolve(options.dest);\n const mod = await esbuildRequire<{ default: IconFontConfig }>(\n configPath,\n );\n const config = mod.exports.default;\n\n await generate({\n ...config,\n dest,\n });\n },\n );\n\n _cli.help();\n\n _cli.version(pkg.version);\n\n _cli.parse();\n}\n\ncli();\n"],"mappings":";;;;;;;;ACYA,eAAsB,MAAM;CAC1B,MAAM,OAAO,IAAI,WAAW;CAE5B,KACG,OAAO,uBAAuB,oCAAoC,EACjE,SAAS,KAAK,KAAK,QAAQ,IAAI,GAAG,GAAG,sBAAsB,EAC7D,CAAC,CAAC,CACD,QACC,sBACA;oEAC8D,KAAK,MAAM,wBAAwB;;;;;;;;;QAS/F,KAAK,CACT,CAAC,CACA,OACC,OAAO,YAAgC,YAA8B;EACnE,IAAI,CAAC,YAAY;GACf,MAAM,SAAS,MAAM,eAAe;GACpC,IAAI,CAAC,QACH,MAAM,IAAI,iBAAiB,4BAA4B;GAEzD,aAAa,KAAK,KAAK,QAAQ,uBAAuB;EACxD;EAEA,MAAM,OAAO,KAAK,QAAQ,QAAQ,IAAI;EAItC,MAAM,UAAS,MAHG,eAChB,UACF,EAAA,CACmB,QAAQ;EAE3B,MAAM,SAAS;GACb,GAAG;GACH;EACF,CAAC;CACH,CACF;CAEF,KAAK,KAAK;CAEV,KAAK,QAAQA,OAAW;CAExB,KAAK,MAAM;AACb;AAEA,IAAI"}
1
+ {"version":3,"file":"cli.mjs","names":["pkg.version"],"sources":["../src/cli.ts"],"sourcesContent":["import { cac } from 'cac';\nimport path from 'node:path';\nimport { findPackageDir, esbuildRequire } from '@fastkit/node-util';\nimport {\n DEFAULT_DEST_DIRNAME,\n DEFAULT_CONFIG_FILENAME,\n IconFontConfig,\n} from './schema';\nimport { generate } from './generator';\nimport { IconFontGenError } from './logger';\nimport pkg from '../package.json';\n\nexport async function cli() {\n const _cli = cac('icon-font');\n\n _cli\n .option('-d, --dest <string>', 'Destination for generated fonts.', {\n default: path.join(process.cwd(), `${DEFAULT_DEST_DIRNAME}`),\n })\n .command(\n '[config file path]',\n `\nPath of the configuration file. (default: [your package directory]${path.sep}${DEFAULT_CONFIG_FILENAME})\n You must export default <IconFontConfig>.\n\n e.g.\n \\`\\`\\`\n import { createIconFontConfig } from '@fastkit/icon-font-gen';\n\n export default createIconFontConfig({ ... });\n \\`\\`\\`\n `.trim(),\n )\n .action(\n async (configPath: string | undefined, options: { dest: string }) => {\n if (!configPath) {\n const pkgDir = await findPackageDir();\n if (!pkgDir) {\n throw new IconFontGenError('missing package directory.');\n }\n configPath = path.join(pkgDir, DEFAULT_CONFIG_FILENAME);\n }\n\n const dest = path.resolve(options.dest);\n const mod = await esbuildRequire<{ default: IconFontConfig }>(\n configPath,\n );\n const config = mod.exports.default;\n\n await generate({\n ...config,\n dest,\n });\n },\n );\n\n _cli.help();\n\n _cli.version(pkg.version);\n\n _cli.parse();\n}\n\ncli();\n"],"mappings":";;;;;AAYA,eAAsB,MAAM;CAC1B,MAAM,OAAO,IAAI,WAAW;CAE5B,KACG,OAAO,uBAAuB,oCAAoC,EACjE,SAAS,KAAK,KAAK,QAAQ,IAAI,GAAG,GAAG,sBAAsB,EAC7D,CAAC,CAAC,CACD,QACC,sBACA;oEAC8D,KAAK,MAAM,wBAAwB;;;;;;;;;QAS/F,KAAK,CACT,CAAC,CACA,OACC,OAAO,YAAgC,YAA8B;EACnE,IAAI,CAAC,YAAY;GACf,MAAM,SAAS,MAAM,eAAe;GACpC,IAAI,CAAC,QACH,MAAM,IAAI,iBAAiB,4BAA4B;GAEzD,aAAa,KAAK,KAAK,QAAQ,uBAAuB;EACxD;EAEA,MAAM,OAAO,KAAK,QAAQ,QAAQ,IAAI;EAItC,MAAM,UAAS,MAHG,eAChB,UACF,EAAA,CACmB,QAAQ;EAE3B,MAAM,SAAS;GACb,GAAG;GACH;EACF,CAAC;CACH,CACF;CAEF,KAAK,KAAK;CAEV,KAAK,QAAQA,OAAW;CAExB,KAAK,MAAM;AACb;AAEA,IAAI"}
@@ -4,7 +4,7 @@ import fs from "fs-extra";
4
4
  import chokidar from "chokidar";
5
5
  import { EV } from "@fastkit/ev";
6
6
  import { TinyLogger, createTinyError } from "@fastkit/tiny-logger";
7
- //#region src/schemes.ts
7
+ //#region src/schema.ts
8
8
  /**
9
9
  * Every format this package knows how to emit, in the order they are written to
10
10
  * the `@font-face` `src` list. Only the formats actually requested through
@@ -27,6 +27,13 @@ const ICON_FONT_FORMAT_MAP = {
27
27
  svg: "svg",
28
28
  otf: "opentype"
29
29
  };
30
+ /**
31
+ * Module the generated code imports the icon-name registry from, and augments
32
+ * with the names it generated.
33
+ *
34
+ * @see {@link IconFontOptions.runtimeModule}
35
+ */
36
+ const DEFAULT_ICON_FONT_RUNTIME_MODULE = "@fastkit/icon-font";
30
37
  async function resolveRawIconFontEntry(rootDir, rawEntry) {
31
38
  const entry = { ...rawEntry };
32
39
  if (entry.src === "@mdi") {
@@ -64,6 +71,9 @@ const name = "icon-font-gen";
64
71
  const logger = new TinyLogger(name);
65
72
  const IconFontGenError = createTinyError(name);
66
73
  //#endregion
74
+ //#region package.json
75
+ var version = "0.16.3";
76
+ //#endregion
67
77
  //#region src/generator.ts
68
78
  const DEFAULT_OPTIONS = {
69
79
  formats: ["woff2"],
@@ -84,14 +94,14 @@ function mergeDefaults(entry) {
84
94
  ...entry
85
95
  };
86
96
  }
87
- async function generateTS(entry, ids) {
97
+ async function generateTS(entry, ids, runtimeModule) {
88
98
  const code = `
89
99
  /* eslint-disable */
90
100
  // @ts-nocheck
91
101
  ${BANNER}
92
- import type { IconName, IconNameMap } from '@fastkit/icon-font';
93
- import { registerIconNames } from '@fastkit/icon-font';
94
- declare module "@fastkit/icon-font" {
102
+ import type { IconName, IconNameMap } from '${runtimeModule}';
103
+ import { registerIconNames } from '${runtimeModule}';
104
+ declare module "${runtimeModule}" {
95
105
  export interface IconNameMap {
96
106
  ${ids.map((id) => ` '${id}': true,`).join("\n")}
97
107
  }
@@ -99,7 +109,7 @@ ${ids.map((id) => ` '${id}': true,`).join("\n")}
99
109
  export const ICON_NAMES = registerIconNames([
100
110
  ${ids.map((id) => `'${id}'`).join(",\n ")}
101
111
  ]);
102
- export type { IconName, IconNameMap } from '@fastkit/icon-font';
112
+ export type { IconName, IconNameMap } from '${runtimeModule}';
103
113
  `.trim();
104
114
  const fileName = `${entry.name || "icons"}.ts`;
105
115
  const dest = path.resolve(entry.dest, fileName);
@@ -110,10 +120,32 @@ export type { IconName, IconNameMap } from '@fastkit/icon-font';
110
120
  code
111
121
  };
112
122
  }
113
- async function generateEntry(entry) {
123
+ /**
124
+ * What the generated output depends on besides the contents of `src`.
125
+ *
126
+ * The source files are hashed separately; this covers the rest, so that an
127
+ * upgrade of this package — or a change to an option — regenerates instead of
128
+ * leaving the previous output in place. Without it a project whose icons had not
129
+ * changed kept output from an older generator indefinitely, and the only way out
130
+ * was to delete the destination by hand.
131
+ *
132
+ * `src` and `dest` are left out on purpose. `src` is already covered by its own
133
+ * content hash, `dest` holds the meta file so a change to it has nothing to
134
+ * compare against anyway, and keeping absolute paths out of the fingerprint
135
+ * keeps the meta file portable between machines and CI.
136
+ */
137
+ function toHashInputs(options, runtimeModule = DEFAULT_ICON_FONT_RUNTIME_MODULE) {
138
+ const { src, dest, ...rest } = options;
139
+ return {
140
+ generator: version,
141
+ runtimeModule,
142
+ options: rest
143
+ };
144
+ }
145
+ async function generateEntry(entry, runtimeModule = DEFAULT_ICON_FONT_RUNTIME_MODULE) {
114
146
  const options = mergeDefaults(entry);
115
147
  const cssPrefix = `icon-${options.prefix}`;
116
- const hash = new HashComparator(options.src, options.dest);
148
+ const hash = new HashComparator(options.src, options.dest, { inputs: toHashInputs(options, runtimeModule) });
117
149
  const srcHash = await hash.hasChanged();
118
150
  if (!srcHash) {
119
151
  logger.info(`Has not changed files. Skip process. >>> ${options.src}`);
@@ -188,14 +220,14 @@ ${glyphs.map(({ name, code }) => `
188
220
  `).join("\n")}
189
221
  `;
190
222
  await fs.writeFile(path.join(options.dest, `${options.name}.css`), cssCode);
191
- await generateTS(options, glyphs.map(({ name }) => `${options.prefix}${name}`));
223
+ await generateTS(options, glyphs.map(({ name }) => `${options.prefix}${name}`), runtimeModule);
192
224
  await hash.commit(srcHash);
193
225
  return {
194
226
  entry,
195
227
  result
196
228
  };
197
229
  }
198
- async function generateIndex(dest, entries) {
230
+ async function generateIndex(dest, entries, runtimeModule = DEFAULT_ICON_FONT_RUNTIME_MODULE) {
199
231
  const names = entries.map(({ name }) => name);
200
232
  const tsCode = `
201
233
  /* eslint-disable */
@@ -203,8 +235,8 @@ async function generateIndex(dest, entries) {
203
235
  import './index.css';
204
236
  ${BANNER}
205
237
  ${names.map((name, index) => `import './${name}/${name}';`).join("\n")}
206
- export type { IconName } from '@fastkit/icon-font';
207
- export { ICON_NAMES } from '@fastkit/icon-font';
238
+ export type { IconName } from '${runtimeModule}';
239
+ export { ICON_NAMES } from '${runtimeModule}';
208
240
  `.trim();
209
241
  const tsDest = path.join(dest, "index.ts");
210
242
  await fs.writeFile(tsDest, tsCode);
@@ -217,9 +249,10 @@ ${names.map((name) => `@import './${name}/${name}.css';`).join("\n")}
217
249
  await fs.writeFile(cssDest, cssCode);
218
250
  }
219
251
  async function generate(opts) {
252
+ const runtimeModule = opts.runtimeModule ?? "@fastkit/icon-font";
220
253
  await fs.emptyDir(opts.dest);
221
- const entries = (await Promise.all(opts.entries.map((entry) => resolveRawIconFontEntry(opts.dest, entry).then((_entry) => generateEntry(_entry))))).map(({ entry }) => entry);
222
- await generateIndex(opts.dest, entries);
254
+ const entries = (await Promise.all(opts.entries.map((entry) => resolveRawIconFontEntry(opts.dest, entry).then((_entry) => generateEntry(_entry, runtimeModule))))).map(({ entry }) => entry);
255
+ await generateIndex(opts.dest, entries, runtimeModule);
223
256
  }
224
257
  var IconFontRunnerItem = class extends EV {
225
258
  entry;
@@ -249,7 +282,7 @@ var IconFontRunnerItem = class extends EV {
249
282
  }
250
283
  async build() {
251
284
  const entry = await this.resolveEntry();
252
- const result = await generateEntry(entry);
285
+ const result = await generateEntry(entry, this.ctx.runtimeModule);
253
286
  this.emit("build", result);
254
287
  return { entry };
255
288
  }
@@ -265,9 +298,12 @@ var IconFontRunnerItem = class extends EV {
265
298
  var IconFontRunner = class extends EV {
266
299
  items = [];
267
300
  dest;
301
+ /** @see {@link IconFontOptions.runtimeModule} */
302
+ runtimeModule;
268
303
  constructor(opts, watch) {
269
304
  super();
270
305
  this.dest = opts.dest;
306
+ this.runtimeModule = opts.runtimeModule ?? "@fastkit/icon-font";
271
307
  opts.entries.forEach((entry) => {
272
308
  const item = new IconFontRunnerItem(this, entry, watch);
273
309
  item.on("build", (result) => {
@@ -281,7 +317,7 @@ var IconFontRunner = class extends EV {
281
317
  }
282
318
  async buildIndex() {
283
319
  const entries = await Promise.all(this.items.map((item) => item.resolveEntry()));
284
- return generateIndex(this.dest, entries);
320
+ return generateIndex(this.dest, entries, this.runtimeModule);
285
321
  }
286
322
  async run() {
287
323
  await fs.ensureDir(this.dest);
@@ -295,6 +331,6 @@ var IconFontRunner = class extends EV {
295
331
  }
296
332
  };
297
333
  //#endregion
298
- export { generateEntry as a, IconFontGenError as c, ICON_FONT_FORMATS as d, ICON_FONT_FORMAT_MAP as f, generate as i, DEFAULT_CONFIG_FILENAME as l, resolveRawIconFontEntry as m, IconFontRunner as n, generateIndex as o, ceateIconFontConfig as p, IconFontRunnerItem as r, mergeDefaults as s, DEFAULT_OPTIONS as t, DEFAULT_DEST_DIRNAME as u };
334
+ export { resolveRawIconFontEntry as _, generateEntry as a, toHashInputs as c, DEFAULT_CONFIG_FILENAME as d, DEFAULT_DEST_DIRNAME as f, ceateIconFontConfig as g, ICON_FONT_FORMAT_MAP as h, generate as i, version as l, ICON_FONT_FORMATS as m, IconFontRunner as n, generateIndex as o, DEFAULT_ICON_FONT_RUNTIME_MODULE as p, IconFontRunnerItem as r, mergeDefaults as s, DEFAULT_OPTIONS as t, IconFontGenError as u };
299
335
 
300
- //# sourceMappingURL=generator-BzNGBKOM.mjs.map
336
+ //# sourceMappingURL=generator-bCFFCSuU.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"generator-bCFFCSuU.mjs","names":["pkg.version"],"sources":["../src/schema.ts","../src/logger.ts","../package.json","../src/generator.ts"],"sourcesContent":["import type { webfont } from 'webfont';\nimport path from 'node:path';\nimport { installPackage } from '@fastkit/node-util';\n\n/**\n * Derived from webfont's public signature. webfont 12 added an `exports` map\n * that only publishes the package root, so its internal `dist` type paths are no\n * longer reachable. Tracking the upstream union means a format added there shows\n * up here as a missing key in {@link ICON_FONT_FORMAT_MAP}.\n */\nexport type IconFontFormat = NonNullable<\n NonNullable<Parameters<typeof webfont>[0]>['formats']\n>[number];\n\n/**\n * Every format this package knows how to emit, in the order they are written to\n * the `@font-face` `src` list. Only the formats actually requested through\n * `formats` are generated, so appending to this list does not change the output\n * of an existing configuration.\n */\nexport const ICON_FONT_FORMATS: IconFontFormat[] = [\n 'eot',\n 'woff',\n 'woff2',\n 'svg',\n 'ttf',\n 'otf',\n];\n\nexport const ICON_FONT_FORMAT_MAP: Record<IconFontFormat, string> = {\n eot: 'embedded-opentype',\n woff2: 'woff2',\n woff: 'woff',\n ttf: 'truetype',\n svg: 'svg',\n otf: 'opentype',\n};\n\nexport interface IconFontSettings {\n fixedWidth?: boolean;\n centerHorizontally?: boolean;\n normalize?: boolean;\n fontHeight?: number;\n round?: number;\n descent?: number;\n disablePrefix?: boolean;\n absolutePath?: boolean;\n addHashInFontUrl?: boolean;\n}\n\nexport interface IconFontEntry extends IconFontSettings {\n name: string;\n fontName: string;\n formats?: IconFontFormat[];\n startUnicode?: number;\n prefix: string;\n src: string;\n dest: string;\n display: 'block' | 'swap';\n}\n\nexport interface RawIconFontEntry extends Omit<\n IconFontEntry,\n 'name' | 'fontName' | 'prefix' | 'dest' | 'display'\n> {\n name?: string;\n fontName?: string;\n /**\n * @default block\n */\n display?: 'block' | 'swap';\n}\n\n// export type RawIconFontOptions = IconFontEntry | IconFontEntry[];\n\n/**\n * Module the generated code imports the icon-name registry from, and augments\n * with the names it generated.\n *\n * @see {@link IconFontOptions.runtimeModule}\n */\nexport const DEFAULT_ICON_FONT_RUNTIME_MODULE = '@fastkit/icon-font';\n\nexport interface IconFontOptions {\n entries: RawIconFontEntry[];\n dest: string;\n /**\n * Module the generated code imports `registerIconNames` / `IconName` from,\n * and whose `IconNameMap` it augments with the generated names.\n *\n * The generated files live in the *consuming* project, so this specifier is\n * resolved from there -- and pnpm places into a project's `node_modules` only\n * what the project itself declares, not what a peer declaration asks for. So\n * whatever this names becomes a package the project has to declare.\n *\n * Point it at a module the project already declares and that re-exports\n * `@fastkit/icon-font` -- a UI kit built on it, say -- and the project needs\n * nothing beyond that kit. Module augmentation follows a re-export to the\n * interface it aliases, so `IconNameMap` still merges into the one\n * `@fastkit/icon-font` declares, and every type derived from it agrees.\n *\n * @default '@fastkit/icon-font'\n */\n runtimeModule?: string;\n}\n\nexport async function resolveRawIconFontEntry(\n rootDir: string,\n rawEntry: RawIconFontEntry,\n): Promise<IconFontEntry> {\n const entry = {\n ...rawEntry,\n };\n\n // mdi support\n if (entry.src === '@mdi') {\n const installedDir = await findOrInstallMDI();\n entry.src = path.join(installedDir, 'svg');\n if (entry.fontHeight == null) {\n entry.fontHeight = 512;\n }\n if (entry.descent == null) {\n entry.descent = 64;\n }\n if (entry.name == null) {\n entry.name = 'mdi';\n }\n }\n\n const name = entry.name || path.basename(entry.src);\n const fontName = entry.fontName || `${name}-icon`;\n const dest = path.join(rootDir, name);\n const prefix = entry.disablePrefix ? '' : `${name}-`;\n const display = entry.display || 'block';\n return {\n ...entry,\n name,\n fontName,\n prefix,\n dest,\n display,\n };\n}\n\nfunction findOrInstallMDI() {\n return installPackage('@mdi/svg', { dev: true });\n}\n\nexport const DEFAULT_CONFIG_FILENAME = 'icon-font.config';\n\nexport const DEFAULT_DEST_DIRNAME = '.icon-font';\n\nexport interface IconFontConfig extends Omit<IconFontOptions, 'dest'> {\n dest?: string;\n}\n\nexport function ceateIconFontConfig(options: IconFontConfig) {\n return options;\n}\n","import { TinyLogger, createTinyError } from '@fastkit/tiny-logger';\n\nconst name = 'icon-font-gen';\n\nexport const logger = new TinyLogger(name);\n\nexport const IconFontGenError = createTinyError(name);\n","","import fs from 'fs-extra';\nimport path from 'node:path';\nimport chokidar, { FSWatcher } from 'chokidar';\nimport { EV } from '@fastkit/ev';\nimport { HashComparator } from '@fastkit/node-util';\nimport { UnPromisify } from '@fastkit/helpers';\nimport type webfont from 'webfont';\nimport { logger } from './logger';\nimport pkg from '../package.json';\nimport {\n IconFontOptions,\n IconFontEntry,\n RawIconFontEntry,\n resolveRawIconFontEntry,\n ICON_FONT_FORMATS,\n IconFontFormat,\n ICON_FONT_FORMAT_MAP,\n DEFAULT_ICON_FONT_RUNTIME_MODULE,\n} from './schema';\n\nexport type IconFontEntryResult = {\n entry: IconFontEntry;\n result?: UnPromisify<ReturnType<typeof webfont>>;\n};\n\nexport const DEFAULT_OPTIONS: Partial<IconFontEntry> = {\n formats: ['woff2'],\n fixedWidth: true,\n normalize: true,\n};\n\nconst BANNER = `\n/**\n * This is auto generated file.\n * Do not edit !!!\n *\n * @see: https://github.com/dadajam4/fastkit/tree/main/packages/icon-font-gen\n */\n`.trim();\n\nexport function mergeDefaults(entry: IconFontEntry): IconFontEntry {\n return {\n ...DEFAULT_OPTIONS,\n ...entry,\n };\n}\n\nasync function generateTS(\n entry: IconFontEntry,\n ids: string[],\n runtimeModule: string,\n) {\n const code = `\n/* eslint-disable */\n// @ts-nocheck\n${BANNER}\nimport type { IconName, IconNameMap } from '${runtimeModule}';\nimport { registerIconNames } from '${runtimeModule}';\ndeclare module \"${runtimeModule}\" {\n export interface IconNameMap {\n${ids.map((id) => ` '${id}': true,`).join('\\n')}\n }\n}\nexport const ICON_NAMES = registerIconNames([\n ${ids.map((id) => `'${id}'`).join(',\\n ')}\n]);\nexport type { IconName, IconNameMap } from '${runtimeModule}';\n `.trim();\n const fileName = `${entry.name || 'icons'}.ts`;\n const dest = path.resolve(entry.dest, fileName);\n await fs.writeFile(dest, code);\n return {\n fileName,\n dest,\n code,\n };\n}\n\n/**\n * What the generated output depends on besides the contents of `src`.\n *\n * The source files are hashed separately; this covers the rest, so that an\n * upgrade of this package — or a change to an option — regenerates instead of\n * leaving the previous output in place. Without it a project whose icons had not\n * changed kept output from an older generator indefinitely, and the only way out\n * was to delete the destination by hand.\n *\n * `src` and `dest` are left out on purpose. `src` is already covered by its own\n * content hash, `dest` holds the meta file so a change to it has nothing to\n * compare against anyway, and keeping absolute paths out of the fingerprint\n * keeps the meta file portable between machines and CI.\n */\nexport function toHashInputs(\n options: IconFontEntry,\n runtimeModule: string = DEFAULT_ICON_FONT_RUNTIME_MODULE,\n) {\n const { src, dest, ...rest } = options;\n return { generator: pkg.version, runtimeModule, options: rest };\n}\n\nexport async function generateEntry(\n entry: IconFontEntry,\n runtimeModule: string = DEFAULT_ICON_FONT_RUNTIME_MODULE,\n): Promise<IconFontEntryResult> {\n const options = mergeDefaults(entry);\n\n // @TODO support empty prefix\n // const namePrefix = options.name;\n const cssPrefix = `icon-${options.prefix}`;\n\n const hash = new HashComparator(options.src, options.dest, {\n inputs: toHashInputs(options, runtimeModule),\n });\n const srcHash = await hash.hasChanged();\n if (!srcHash) {\n logger.info(`Has not changed files. Skip process. >>> ${options.src}`);\n return { entry };\n }\n\n await fs.ensureDir(options.dest);\n\n const { webfont } = await import('webfont');\n\n // const { startUnicode = 0xea01 } = options;\n const { startUnicode = 0xba01 } = options;\n\n let i = startUnicode;\n\n const result = await webfont({\n files: options.src,\n fontName: options.fontName,\n formats: options.formats,\n fixedWidth: options.fixedWidth,\n centerHorizontally: options.centerHorizontally,\n normalize: options.normalize,\n fontHeight: options.fontHeight,\n round: options.round,\n descent: options.descent,\n addHashInFontUrl: options.addHashInFontUrl,\n glyphTransformFn: (obj) => {\n const char = String.fromCodePoint(i);\n obj.unicode = [char];\n i++;\n return obj;\n },\n });\n\n const buildedFormats: { format: IconFontFormat; code: string | Buffer }[] =\n [];\n ICON_FONT_FORMATS.forEach((format) => {\n const code = result[format];\n if (code) {\n buildedFormats.push({ format, code });\n }\n });\n\n await Promise.all(\n buildedFormats.map(({ format, code }) =>\n fs.writeFile(\n path.join(options.dest, `${options.name}.${format}`),\n code as string | Uint8Array,\n ),\n ),\n );\n\n const glyphs: { name: string; code: string }[] = [];\n\n result.glyphsData!.forEach(({ metadata }) => {\n if (!metadata) return;\n const { name, unicode } = metadata;\n if (!unicode) {\n return;\n }\n\n const code = unicode[0].charCodeAt(0).toString(16);\n glyphs.push({ name, code });\n });\n\n const urlPath = options.absolutePath ? options.dest : '.';\n const hashSuffix = options.addHashInFontUrl ? `?${Date.now()}` : '';\n const src = buildedFormats\n .map(\n ({ format }) =>\n `url(\"${urlPath}/${options.name}.${format}${hashSuffix}\") format(\"${ICON_FONT_FORMAT_MAP[format]}\")`,\n )\n .join(',');\n\n const cssCode = `/* stylelint-disable */\n@font-face {\n font-family: \"${options.fontName}\";\n font-display: ${options.display};\n font-style: normal;\n font-weight: 400;\n src: ${src};\n}\n\ni[class^=\"${cssPrefix}\"]:before, i[class*=\" ${cssPrefix}\"]:before {\n font-family: ${options.fontName} !important;\n font-style: normal;\n font-weight: normal !important;\n font-variant: normal;\n text-transform: none;\n text-rendering: auto;\n line-height: 1;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n${glyphs\n .map(\n ({ name, code }) => `\n.${cssPrefix}${name}:before { content: \"\\\\${code}\"; }\n `,\n )\n .join('\\n')}\n `;\n await fs.writeFile(path.join(options.dest, `${options.name}.css`), cssCode);\n\n // const prefix = options.prefix ? `${options.prefix}-` : '';\n const ids = glyphs.map(({ name }) => `${options.prefix}${name}`);\n await generateTS(options, ids, runtimeModule);\n await hash.commit(srcHash);\n return {\n entry,\n result,\n };\n}\n\nexport async function generateIndex(\n dest: string,\n entries: IconFontEntry[],\n runtimeModule: string = DEFAULT_ICON_FONT_RUNTIME_MODULE,\n) {\n const names = entries.map(({ name }) => name);\n const tsCode = `\n/* eslint-disable */\n// @ts-nocheck\nimport './index.css';\n${BANNER}\n${names\n .map(\n (name, index) =>\n // `import { IconName as IconName_${index}, IconNameMap as IconNameMap_${index} } from './${name}/${name}';`,\n `import './${name}/${name}';`,\n )\n .join('\\n')}\nexport type { IconName } from '${runtimeModule}';\nexport { ICON_NAMES } from '${runtimeModule}';\n `.trim();\n const tsDest = path.join(dest, 'index.ts');\n await fs.writeFile(tsDest, tsCode);\n\n const cssCode = `\n/* stylelint-disable */\n${BANNER}\n${names.map((name) => `@import './${name}/${name}.css';`).join('\\n')}\n `.trim();\n const cssDest = path.join(dest, 'index.css');\n await fs.writeFile(cssDest, cssCode);\n}\n\nexport async function generate(opts: IconFontOptions) {\n const runtimeModule = opts.runtimeModule ?? DEFAULT_ICON_FONT_RUNTIME_MODULE;\n await fs.emptyDir(opts.dest);\n const results = await Promise.all(\n opts.entries.map((entry) =>\n resolveRawIconFontEntry(opts.dest, entry).then((_entry) =>\n generateEntry(_entry, runtimeModule),\n ),\n ),\n );\n const entries = results.map(({ entry }) => entry);\n await generateIndex(opts.dest, entries, runtimeModule);\n}\n\nexport class IconFontRunnerItem extends EV<{\n build: IconFontEntryResult;\n}> {\n readonly entry: RawIconFontEntry;\n\n readonly ctx: IconFontRunner;\n\n private _resolveEntryPromise?: Promise<IconFontEntry>;\n\n private _watcher: FSWatcher | null = null;\n\n watchMode: boolean;\n\n // get name() {\n // return this.entry.name;\n // }\n\n constructor(ctx: IconFontRunner, entry: RawIconFontEntry, watch = false) {\n super();\n this.ctx = ctx;\n this.entry = entry;\n this.watchMode = watch;\n this.build = this.build.bind(this);\n }\n\n async run() {\n const result = await this.build();\n if (this.watchMode && !this._watcher) {\n const watchDir = path.resolve(this.entry.src);\n this._watcher = chokidar.watch(watchDir, { ignoreInitial: true });\n this._watcher.on('all', this.build);\n }\n return result;\n }\n\n resolveEntry() {\n if (!this._resolveEntryPromise) {\n this._resolveEntryPromise = resolveRawIconFontEntry(\n this.ctx.dest,\n this.entry,\n );\n }\n return this._resolveEntryPromise;\n }\n\n async build() {\n const entry = await this.resolveEntry();\n const result = await generateEntry(entry, this.ctx.runtimeModule);\n this.emit('build', result);\n return { entry };\n }\n\n destroy() {\n if (this._watcher) {\n this._watcher.close();\n this._watcher = null;\n }\n this.offAll();\n if (this.ctx) {\n delete (this as any).ctx;\n }\n }\n}\n\nexport class IconFontRunner extends EV<{\n build: {\n item: IconFontRunnerItem;\n result: IconFontEntryResult;\n };\n}> {\n readonly items: IconFontRunnerItem[] = [];\n\n readonly dest: string;\n\n /** @see {@link IconFontOptions.runtimeModule} */\n readonly runtimeModule: string;\n\n constructor(opts: IconFontOptions, watch?: boolean) {\n super();\n\n this.dest = opts.dest;\n this.runtimeModule = opts.runtimeModule ?? DEFAULT_ICON_FONT_RUNTIME_MODULE;\n\n opts.entries.forEach((entry) => {\n const item = new IconFontRunnerItem(this, entry, watch);\n item.on('build', (result) => {\n this.emit('build', { item, result });\n });\n this.items.push(item);\n });\n }\n\n async buildIndex() {\n const entries = await Promise.all(\n this.items.map((item) => item.resolveEntry()),\n );\n return generateIndex(this.dest, entries, this.runtimeModule);\n }\n\n async run() {\n await fs.ensureDir(this.dest);\n await Promise.all([\n this.buildIndex(),\n Promise.all(this.items.map((item) => item.run())),\n ]);\n }\n\n destroy() {\n this.items.forEach((item) => item.destroy());\n this.items.length = 0;\n this.offAll();\n delete (this as any)._opts;\n }\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { EV } from "@fastkit/ev";
2
2
  import webfont, { webfont as webfont$1 } from "webfont";
3
3
  import { UnPromisify } from "@fastkit/helpers";
4
- //#region src/schemes.d.ts
4
+ //#region src/schema.d.ts
5
5
  /**
6
6
  * Derived from webfont's public signature. webfont 12 added an `exports` map
7
7
  * that only publishes the package root, so its internal `dist` type paths are no
@@ -46,9 +46,34 @@ interface RawIconFontEntry extends Omit<IconFontEntry, 'name' | 'fontName' | 'pr
46
46
  */
47
47
  display?: 'block' | 'swap';
48
48
  }
49
+ /**
50
+ * Module the generated code imports the icon-name registry from, and augments
51
+ * with the names it generated.
52
+ *
53
+ * @see {@link IconFontOptions.runtimeModule}
54
+ */
55
+ declare const DEFAULT_ICON_FONT_RUNTIME_MODULE = "@fastkit/icon-font";
49
56
  interface IconFontOptions {
50
57
  entries: RawIconFontEntry[];
51
58
  dest: string;
59
+ /**
60
+ * Module the generated code imports `registerIconNames` / `IconName` from,
61
+ * and whose `IconNameMap` it augments with the generated names.
62
+ *
63
+ * The generated files live in the *consuming* project, so this specifier is
64
+ * resolved from there -- and pnpm places into a project's `node_modules` only
65
+ * what the project itself declares, not what a peer declaration asks for. So
66
+ * whatever this names becomes a package the project has to declare.
67
+ *
68
+ * Point it at a module the project already declares and that re-exports
69
+ * `@fastkit/icon-font` -- a UI kit built on it, say -- and the project needs
70
+ * nothing beyond that kit. Module augmentation follows a re-export to the
71
+ * interface it aliases, so `IconNameMap` still merges into the one
72
+ * `@fastkit/icon-font` declares, and every type derived from it agrees.
73
+ *
74
+ * @default '@fastkit/icon-font'
75
+ */
76
+ runtimeModule?: string;
52
77
  }
53
78
  declare function resolveRawIconFontEntry(rootDir: string, rawEntry: RawIconFontEntry): Promise<IconFontEntry>;
54
79
  declare const DEFAULT_CONFIG_FILENAME = "icon-font.config";
@@ -65,8 +90,43 @@ type IconFontEntryResult = {
65
90
  };
66
91
  declare const DEFAULT_OPTIONS: Partial<IconFontEntry>;
67
92
  declare function mergeDefaults(entry: IconFontEntry): IconFontEntry;
68
- declare function generateEntry(entry: IconFontEntry): Promise<IconFontEntryResult>;
69
- declare function generateIndex(dest: string, entries: IconFontEntry[]): Promise<void>;
93
+ /**
94
+ * What the generated output depends on besides the contents of `src`.
95
+ *
96
+ * The source files are hashed separately; this covers the rest, so that an
97
+ * upgrade of this package — or a change to an option — regenerates instead of
98
+ * leaving the previous output in place. Without it a project whose icons had not
99
+ * changed kept output from an older generator indefinitely, and the only way out
100
+ * was to delete the destination by hand.
101
+ *
102
+ * `src` and `dest` are left out on purpose. `src` is already covered by its own
103
+ * content hash, `dest` holds the meta file so a change to it has nothing to
104
+ * compare against anyway, and keeping absolute paths out of the fingerprint
105
+ * keeps the meta file portable between machines and CI.
106
+ */
107
+ declare function toHashInputs(options: IconFontEntry, runtimeModule?: string): {
108
+ generator: string;
109
+ runtimeModule: string;
110
+ options: {
111
+ name: string;
112
+ fontName: string;
113
+ formats?: IconFontFormat[];
114
+ startUnicode?: number;
115
+ prefix: string;
116
+ display: "block" | "swap";
117
+ fixedWidth?: boolean;
118
+ centerHorizontally?: boolean;
119
+ normalize?: boolean;
120
+ fontHeight?: number;
121
+ round?: number;
122
+ descent?: number;
123
+ disablePrefix?: boolean;
124
+ absolutePath?: boolean;
125
+ addHashInFontUrl?: boolean;
126
+ };
127
+ };
128
+ declare function generateEntry(entry: IconFontEntry, runtimeModule?: string): Promise<IconFontEntryResult>;
129
+ declare function generateIndex(dest: string, entries: IconFontEntry[], runtimeModule?: string): Promise<void>;
70
130
  declare function generate(opts: IconFontOptions): Promise<void>;
71
131
  declare class IconFontRunnerItem extends EV<{
72
132
  build: IconFontEntryResult;
@@ -94,10 +154,12 @@ declare class IconFontRunner extends EV<{
94
154
  }> {
95
155
  readonly items: IconFontRunnerItem[];
96
156
  readonly dest: string;
157
+ /** @see {@link IconFontOptions.runtimeModule} */
158
+ readonly runtimeModule: string;
97
159
  constructor(opts: IconFontOptions, watch?: boolean);
98
160
  buildIndex(): Promise<void>;
99
161
  run(): Promise<void>;
100
162
  destroy(): void;
101
163
  }
102
164
  //#endregion
103
- export { DEFAULT_CONFIG_FILENAME, DEFAULT_DEST_DIRNAME, DEFAULT_OPTIONS, ICON_FONT_FORMATS, ICON_FONT_FORMAT_MAP, IconFontConfig, IconFontEntry, IconFontEntryResult, IconFontFormat, IconFontOptions, IconFontRunner, IconFontRunnerItem, IconFontSettings, RawIconFontEntry, ceateIconFontConfig, generate, generateEntry, generateIndex, mergeDefaults, resolveRawIconFontEntry };
165
+ export { DEFAULT_CONFIG_FILENAME, DEFAULT_DEST_DIRNAME, DEFAULT_ICON_FONT_RUNTIME_MODULE, DEFAULT_OPTIONS, ICON_FONT_FORMATS, ICON_FONT_FORMAT_MAP, IconFontConfig, IconFontEntry, IconFontEntryResult, IconFontFormat, IconFontOptions, IconFontRunner, IconFontRunnerItem, IconFontSettings, RawIconFontEntry, ceateIconFontConfig, generate, generateEntry, generateIndex, mergeDefaults, resolveRawIconFontEntry, toHashInputs };
@@ -1,2 +1,2 @@
1
- import { a as generateEntry, d as ICON_FONT_FORMATS, f as ICON_FONT_FORMAT_MAP, i as generate, l as DEFAULT_CONFIG_FILENAME, m as resolveRawIconFontEntry, n as IconFontRunner, o as generateIndex, p as ceateIconFontConfig, r as IconFontRunnerItem, s as mergeDefaults, t as DEFAULT_OPTIONS, u as DEFAULT_DEST_DIRNAME } from "./generator-BzNGBKOM.mjs";
2
- export { DEFAULT_CONFIG_FILENAME, DEFAULT_DEST_DIRNAME, DEFAULT_OPTIONS, ICON_FONT_FORMATS, ICON_FONT_FORMAT_MAP, IconFontRunner, IconFontRunnerItem, ceateIconFontConfig, generate, generateEntry, generateIndex, mergeDefaults, resolveRawIconFontEntry };
1
+ import { _ as resolveRawIconFontEntry, a as generateEntry, c as toHashInputs, d as DEFAULT_CONFIG_FILENAME, f as DEFAULT_DEST_DIRNAME, g as ceateIconFontConfig, h as ICON_FONT_FORMAT_MAP, i as generate, m as ICON_FONT_FORMATS, n as IconFontRunner, o as generateIndex, p as DEFAULT_ICON_FONT_RUNTIME_MODULE, r as IconFontRunnerItem, s as mergeDefaults, t as DEFAULT_OPTIONS } from "./generator-bCFFCSuU.mjs";
2
+ export { DEFAULT_CONFIG_FILENAME, DEFAULT_DEST_DIRNAME, DEFAULT_ICON_FONT_RUNTIME_MODULE, DEFAULT_OPTIONS, ICON_FONT_FORMATS, ICON_FONT_FORMAT_MAP, IconFontRunner, IconFontRunnerItem, ceateIconFontConfig, generate, generateEntry, generateIndex, mergeDefaults, resolveRawIconFontEntry, toHashInputs };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fastkit/icon-font-gen",
3
- "version": "0.16.2",
3
+ "version": "0.16.3",
4
4
  "description": "A tool to generate icon web fonts and their definitions Type-safe for your application.",
5
5
  "keywords": [
6
6
  "fastkit",
@@ -58,10 +58,17 @@
58
58
  "fs-extra": "^11.4.0",
59
59
  "webfont": "^12.5.0",
60
60
  "@fastkit/ev": "^0.15.2",
61
- "@fastkit/helpers": "^0.16.2",
62
- "@fastkit/icon-font": "^2.2.3",
63
- "@fastkit/node-util": "^0.16.2",
64
- "@fastkit/tiny-logger": "^0.16.2"
61
+ "@fastkit/helpers": "^0.17.0",
62
+ "@fastkit/node-util": "^0.17.0",
63
+ "@fastkit/tiny-logger": "^0.16.3"
64
+ },
65
+ "peerDependencies": {
66
+ "@fastkit/icon-font": "^2.2.3"
67
+ },
68
+ "peerDependenciesMeta": {
69
+ "@fastkit/icon-font": {
70
+ "optional": true
71
+ }
65
72
  },
66
73
  "buildOptions": {
67
74
  "name": "IconFont"
@@ -1 +0,0 @@
1
- {"version":3,"file":"generator-BzNGBKOM.mjs","names":[],"sources":["../src/schemes.ts","../src/logger.ts","../src/generator.ts"],"sourcesContent":["import type { webfont } from 'webfont';\nimport path from 'node:path';\nimport { installPackage } from '@fastkit/node-util';\n\n/**\n * Derived from webfont's public signature. webfont 12 added an `exports` map\n * that only publishes the package root, so its internal `dist` type paths are no\n * longer reachable. Tracking the upstream union means a format added there shows\n * up here as a missing key in {@link ICON_FONT_FORMAT_MAP}.\n */\nexport type IconFontFormat = NonNullable<\n NonNullable<Parameters<typeof webfont>[0]>['formats']\n>[number];\n\n/**\n * Every format this package knows how to emit, in the order they are written to\n * the `@font-face` `src` list. Only the formats actually requested through\n * `formats` are generated, so appending to this list does not change the output\n * of an existing configuration.\n */\nexport const ICON_FONT_FORMATS: IconFontFormat[] = [\n 'eot',\n 'woff',\n 'woff2',\n 'svg',\n 'ttf',\n 'otf',\n];\n\nexport const ICON_FONT_FORMAT_MAP: Record<IconFontFormat, string> = {\n eot: 'embedded-opentype',\n woff2: 'woff2',\n woff: 'woff',\n ttf: 'truetype',\n svg: 'svg',\n otf: 'opentype',\n};\n\nexport interface IconFontSettings {\n fixedWidth?: boolean;\n centerHorizontally?: boolean;\n normalize?: boolean;\n fontHeight?: number;\n round?: number;\n descent?: number;\n disablePrefix?: boolean;\n absolutePath?: boolean;\n addHashInFontUrl?: boolean;\n}\n\nexport interface IconFontEntry extends IconFontSettings {\n name: string;\n fontName: string;\n formats?: IconFontFormat[];\n startUnicode?: number;\n prefix: string;\n src: string;\n dest: string;\n display: 'block' | 'swap';\n}\n\nexport interface RawIconFontEntry extends Omit<\n IconFontEntry,\n 'name' | 'fontName' | 'prefix' | 'dest' | 'display'\n> {\n name?: string;\n fontName?: string;\n /**\n * @default block\n */\n display?: 'block' | 'swap';\n}\n\n// export type RawIconFontOptions = IconFontEntry | IconFontEntry[];\n\nexport interface IconFontOptions {\n entries: RawIconFontEntry[];\n dest: string;\n}\n\nexport async function resolveRawIconFontEntry(\n rootDir: string,\n rawEntry: RawIconFontEntry,\n): Promise<IconFontEntry> {\n const entry = {\n ...rawEntry,\n };\n\n // mdi support\n if (entry.src === '@mdi') {\n const installedDir = await findOrInstallMDI();\n entry.src = path.join(installedDir, 'svg');\n if (entry.fontHeight == null) {\n entry.fontHeight = 512;\n }\n if (entry.descent == null) {\n entry.descent = 64;\n }\n if (entry.name == null) {\n entry.name = 'mdi';\n }\n }\n\n const name = entry.name || path.basename(entry.src);\n const fontName = entry.fontName || `${name}-icon`;\n const dest = path.join(rootDir, name);\n const prefix = entry.disablePrefix ? '' : `${name}-`;\n const display = entry.display || 'block';\n return {\n ...entry,\n name,\n fontName,\n prefix,\n dest,\n display,\n };\n}\n\nfunction findOrInstallMDI() {\n return installPackage('@mdi/svg', { dev: true });\n}\n\nexport const DEFAULT_CONFIG_FILENAME = 'icon-font.config';\n\nexport const DEFAULT_DEST_DIRNAME = '.icon-font';\n\nexport interface IconFontConfig extends Omit<IconFontOptions, 'dest'> {\n dest?: string;\n}\n\nexport function ceateIconFontConfig(options: IconFontConfig) {\n return options;\n}\n","import { TinyLogger, createTinyError } from '@fastkit/tiny-logger';\n\nconst name = 'icon-font-gen';\n\nexport const logger = new TinyLogger(name);\n\nexport const IconFontGenError = createTinyError(name);\n","import fs from 'fs-extra';\nimport path from 'node:path';\nimport chokidar, { FSWatcher } from 'chokidar';\nimport { EV } from '@fastkit/ev';\nimport { HashComparator } from '@fastkit/node-util';\nimport { UnPromisify } from '@fastkit/helpers';\nimport type webfont from 'webfont';\nimport { logger } from './logger';\nimport {\n IconFontOptions,\n IconFontEntry,\n RawIconFontEntry,\n resolveRawIconFontEntry,\n ICON_FONT_FORMATS,\n IconFontFormat,\n ICON_FONT_FORMAT_MAP,\n} from './schemes';\n\nexport type IconFontEntryResult = {\n entry: IconFontEntry;\n result?: UnPromisify<ReturnType<typeof webfont>>;\n};\n\nexport const DEFAULT_OPTIONS: Partial<IconFontEntry> = {\n formats: ['woff2'],\n fixedWidth: true,\n normalize: true,\n};\n\nconst BANNER = `\n/**\n * This is auto generated file.\n * Do not edit !!!\n *\n * @see: https://github.com/dadajam4/fastkit/tree/main/packages/icon-font-gen\n */\n`.trim();\n\nexport function mergeDefaults(entry: IconFontEntry): IconFontEntry {\n return {\n ...DEFAULT_OPTIONS,\n ...entry,\n };\n}\n\nasync function generateTS(entry: IconFontEntry, ids: string[]) {\n const code = `\n/* eslint-disable */\n// @ts-nocheck\n${BANNER}\nimport type { IconName, IconNameMap } from '@fastkit/icon-font';\nimport { registerIconNames } from '@fastkit/icon-font';\ndeclare module \"@fastkit/icon-font\" {\n export interface IconNameMap {\n${ids.map((id) => ` '${id}': true,`).join('\\n')}\n }\n}\nexport const ICON_NAMES = registerIconNames([\n ${ids.map((id) => `'${id}'`).join(',\\n ')}\n]);\nexport type { IconName, IconNameMap } from '@fastkit/icon-font';\n `.trim();\n const fileName = `${entry.name || 'icons'}.ts`;\n const dest = path.resolve(entry.dest, fileName);\n await fs.writeFile(dest, code);\n return {\n fileName,\n dest,\n code,\n };\n}\n\nexport async function generateEntry(\n entry: IconFontEntry,\n): Promise<IconFontEntryResult> {\n const options = mergeDefaults(entry);\n\n // @TODO support empty prefix\n // const namePrefix = options.name;\n const cssPrefix = `icon-${options.prefix}`;\n\n const hash = new HashComparator(options.src, options.dest);\n const srcHash = await hash.hasChanged();\n if (!srcHash) {\n logger.info(`Has not changed files. Skip process. >>> ${options.src}`);\n return { entry };\n }\n\n await fs.ensureDir(options.dest);\n\n const { webfont } = await import('webfont');\n\n // const { startUnicode = 0xea01 } = options;\n const { startUnicode = 0xba01 } = options;\n\n let i = startUnicode;\n\n const result = await webfont({\n files: options.src,\n fontName: options.fontName,\n formats: options.formats,\n fixedWidth: options.fixedWidth,\n centerHorizontally: options.centerHorizontally,\n normalize: options.normalize,\n fontHeight: options.fontHeight,\n round: options.round,\n descent: options.descent,\n addHashInFontUrl: options.addHashInFontUrl,\n glyphTransformFn: (obj) => {\n const char = String.fromCodePoint(i);\n obj.unicode = [char];\n i++;\n return obj;\n },\n });\n\n const buildedFormats: { format: IconFontFormat; code: string | Buffer }[] =\n [];\n ICON_FONT_FORMATS.forEach((format) => {\n const code = result[format];\n if (code) {\n buildedFormats.push({ format, code });\n }\n });\n\n await Promise.all(\n buildedFormats.map(({ format, code }) =>\n fs.writeFile(\n path.join(options.dest, `${options.name}.${format}`),\n code as string | Uint8Array,\n ),\n ),\n );\n\n const glyphs: { name: string; code: string }[] = [];\n\n result.glyphsData!.forEach(({ metadata }) => {\n if (!metadata) return;\n const { name, unicode } = metadata;\n if (!unicode) {\n return;\n }\n\n const code = unicode[0].charCodeAt(0).toString(16);\n glyphs.push({ name, code });\n });\n\n const urlPath = options.absolutePath ? options.dest : '.';\n const hashSuffix = options.addHashInFontUrl ? `?${Date.now()}` : '';\n const src = buildedFormats\n .map(\n ({ format }) =>\n `url(\"${urlPath}/${options.name}.${format}${hashSuffix}\") format(\"${ICON_FONT_FORMAT_MAP[format]}\")`,\n )\n .join(',');\n\n const cssCode = `/* stylelint-disable */\n@font-face {\n font-family: \"${options.fontName}\";\n font-display: ${options.display};\n font-style: normal;\n font-weight: 400;\n src: ${src};\n}\n\ni[class^=\"${cssPrefix}\"]:before, i[class*=\" ${cssPrefix}\"]:before {\n font-family: ${options.fontName} !important;\n font-style: normal;\n font-weight: normal !important;\n font-variant: normal;\n text-transform: none;\n text-rendering: auto;\n line-height: 1;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n${glyphs\n .map(\n ({ name, code }) => `\n.${cssPrefix}${name}:before { content: \"\\\\${code}\"; }\n `,\n )\n .join('\\n')}\n `;\n await fs.writeFile(path.join(options.dest, `${options.name}.css`), cssCode);\n\n // const prefix = options.prefix ? `${options.prefix}-` : '';\n const ids = glyphs.map(({ name }) => `${options.prefix}${name}`);\n await generateTS(options, ids);\n await hash.commit(srcHash);\n return {\n entry,\n result,\n };\n}\n\nexport async function generateIndex(dest: string, entries: IconFontEntry[]) {\n const names = entries.map(({ name }) => name);\n const tsCode = `\n/* eslint-disable */\n// @ts-nocheck\nimport './index.css';\n${BANNER}\n${names\n .map(\n (name, index) =>\n // `import { IconName as IconName_${index}, IconNameMap as IconNameMap_${index} } from './${name}/${name}';`,\n `import './${name}/${name}';`,\n )\n .join('\\n')}\nexport type { IconName } from '@fastkit/icon-font';\nexport { ICON_NAMES } from '@fastkit/icon-font';\n `.trim();\n const tsDest = path.join(dest, 'index.ts');\n await fs.writeFile(tsDest, tsCode);\n\n const cssCode = `\n/* stylelint-disable */\n${BANNER}\n${names.map((name) => `@import './${name}/${name}.css';`).join('\\n')}\n `.trim();\n const cssDest = path.join(dest, 'index.css');\n await fs.writeFile(cssDest, cssCode);\n}\n\nexport async function generate(opts: IconFontOptions) {\n await fs.emptyDir(opts.dest);\n const results = await Promise.all(\n opts.entries.map((entry) =>\n resolveRawIconFontEntry(opts.dest, entry).then((_entry) =>\n generateEntry(_entry),\n ),\n ),\n );\n const entries = results.map(({ entry }) => entry);\n await generateIndex(opts.dest, entries);\n}\n\nexport class IconFontRunnerItem extends EV<{\n build: IconFontEntryResult;\n}> {\n readonly entry: RawIconFontEntry;\n\n readonly ctx: IconFontRunner;\n\n private _resolveEntryPromise?: Promise<IconFontEntry>;\n\n private _watcher: FSWatcher | null = null;\n\n watchMode: boolean;\n\n // get name() {\n // return this.entry.name;\n // }\n\n constructor(ctx: IconFontRunner, entry: RawIconFontEntry, watch = false) {\n super();\n this.ctx = ctx;\n this.entry = entry;\n this.watchMode = watch;\n this.build = this.build.bind(this);\n }\n\n async run() {\n const result = await this.build();\n if (this.watchMode && !this._watcher) {\n const watchDir = path.resolve(this.entry.src);\n this._watcher = chokidar.watch(watchDir, { ignoreInitial: true });\n this._watcher.on('all', this.build);\n }\n return result;\n }\n\n resolveEntry() {\n if (!this._resolveEntryPromise) {\n this._resolveEntryPromise = resolveRawIconFontEntry(\n this.ctx.dest,\n this.entry,\n );\n }\n return this._resolveEntryPromise;\n }\n\n async build() {\n const entry = await this.resolveEntry();\n const result = await generateEntry(entry);\n this.emit('build', result);\n return { entry };\n }\n\n destroy() {\n if (this._watcher) {\n this._watcher.close();\n this._watcher = null;\n }\n this.offAll();\n if (this.ctx) {\n delete (this as any).ctx;\n }\n }\n}\n\nexport class IconFontRunner extends EV<{\n build: {\n item: IconFontRunnerItem;\n result: IconFontEntryResult;\n };\n}> {\n readonly items: IconFontRunnerItem[] = [];\n\n readonly dest: string;\n\n constructor(opts: IconFontOptions, watch?: boolean) {\n super();\n\n this.dest = opts.dest;\n\n opts.entries.forEach((entry) => {\n const item = new IconFontRunnerItem(this, entry, watch);\n item.on('build', (result) => {\n this.emit('build', { item, result });\n });\n this.items.push(item);\n });\n }\n\n async buildIndex() {\n const entries = await Promise.all(\n this.items.map((item) => item.resolveEntry()),\n );\n return generateIndex(this.dest, entries);\n }\n\n async run() {\n await fs.ensureDir(this.dest);\n await Promise.all([\n this.buildIndex(),\n Promise.all(this.items.map((item) => item.run())),\n ]);\n }\n\n destroy() {\n this.items.forEach((item) => item.destroy());\n this.items.length = 0;\n this.offAll();\n delete (this as any)._opts;\n }\n}\n"],"mappings":"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"}