@jayson991/svg2font 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,156 @@
1
+ # @jayson991/svg2font
2
+
3
+ > Generate icon fonts from SVG files — TypeScript/WASM library
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@jayson991/svg2font.svg)](https://www.npmjs.com/package/@jayson991/svg2font)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
7
+ [![Node.js Version](https://img.shields.io/node/v/@jayson991/svg2font.svg)](https://nodejs.org/)
8
+
9
+ A WebAssembly module wrapping the same Rust core as the CLI. Provides full TypeScript types and `async/await` support. Zero JavaScript font dependencies — all font generation happens in Rust compiled to WASM.
10
+
11
+ For the CLI tool, see [`@jayson991/svg2font-cli`](../svg2font-cli/README.md).
12
+
13
+ ## Requirements
14
+
15
+ - Node.js 18 or higher
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install @jayson991/svg2font
21
+
22
+ # Or with pnpm
23
+ pnpm add @jayson991/svg2font
24
+
25
+ # Or with yarn
26
+ yarn add @jayson991/svg2font
27
+ ```
28
+
29
+ ## Quick Start
30
+
31
+ ```typescript
32
+ import { generate } from '@jayson991/svg2font';
33
+
34
+ const result = await generate({
35
+ src: 'icons/**/*.svg',
36
+ dist: 'dist',
37
+ fontName: 'myicons',
38
+ });
39
+
40
+ console.log(`Generated ${result.glyphs.length} icons`);
41
+ console.log(`Bundle: ${result.zipPath}`);
42
+ ```
43
+
44
+ ## API
45
+
46
+ ### `generate(options): Promise<GenerateResult>`
47
+
48
+ ```typescript
49
+ export function generate(options: GenerateOptions): Promise<GenerateResult>;
50
+ ```
51
+
52
+ #### GenerateOptions
53
+
54
+ | Field | Type | Required | Default | Description |
55
+ |-------|------|----------|---------|-------------|
56
+ | `src` | `string` | Yes | — | Glob pattern for source SVG files (e.g. `"icons/**/*.svg"`) |
57
+ | `dist` | `string` | Yes | — | Output directory |
58
+ | `fontName` | `string` | Yes | — | Font family name used in file names and CSS |
59
+ | `prefix` | `string` | No | `"icon"` | CSS class prefix |
60
+ | `startCodepoint` | `number` | No | `57345` (0xe001) | Starting Unicode codepoint |
61
+
62
+ #### GenerateResult
63
+
64
+ | Field | Type | Description |
65
+ |-------|------|-------------|
66
+ | `glyphs` | `GlyphMeta[]` | Metadata for every generated icon |
67
+ | `zipPath` | `string` | Absolute path to the generated ZIP archive |
68
+
69
+ #### GlyphMeta
70
+
71
+ | Field | Type | Description |
72
+ |-------|------|-------------|
73
+ | `name` | `string` | Icon name in kebab-case (e.g. `"arrow-right"`) |
74
+ | `codepoint` | `number` | Assigned Unicode codepoint (e.g. `57345`) |
75
+ | `unicode` | `string` | HTML entity (e.g. `"&#xe001;"`) |
76
+ | `className` | `string` | Full CSS class name (e.g. `"icon-arrow-right"`) |
77
+
78
+ ## Examples
79
+
80
+ ### Basic usage
81
+
82
+ ```typescript
83
+ import { generate } from '@jayson991/svg2font';
84
+
85
+ const result = await generate({
86
+ src: 'src/assets/icons/**/*.svg',
87
+ dist: 'public/fonts',
88
+ fontName: 'myicons',
89
+ prefix: 'icon',
90
+ });
91
+
92
+ for (const glyph of result.glyphs) {
93
+ console.log(`${glyph.className} → ${glyph.unicode}`);
94
+ }
95
+ ```
96
+
97
+ ### Custom codepoint range
98
+
99
+ ```typescript
100
+ import { generate } from '@jayson991/svg2font';
101
+ import { writeFileSync } from 'fs';
102
+
103
+ const result = await generate({
104
+ src: 'icons/**/*.svg',
105
+ dist: 'dist',
106
+ fontName: 'design-system',
107
+ prefix: 'ds',
108
+ startCodepoint: 0xf000,
109
+ });
110
+
111
+ // Write a custom mapping file
112
+ const mapping = Object.fromEntries(
113
+ result.glyphs.map(g => [g.name, { unicode: g.unicode, className: g.className }])
114
+ );
115
+ writeFileSync('icon-map.json', JSON.stringify(mapping, null, 2));
116
+ ```
117
+
118
+ ### Build script integration
119
+
120
+ ```typescript
121
+ // scripts/build-icons.ts
122
+ import { generate } from '@jayson991/svg2font';
123
+
124
+ async function main() {
125
+ const result = await generate({
126
+ src: 'design/icons/**/*.svg',
127
+ dist: 'src/assets/fonts',
128
+ fontName: 'app-icons',
129
+ prefix: 'icon',
130
+ });
131
+ console.log(`Built ${result.glyphs.length} icons → ${result.zipPath}`);
132
+ }
133
+
134
+ main().catch(console.error);
135
+ ```
136
+
137
+ ## Output
138
+
139
+ The `dist/{fontName}/` directory is created containing:
140
+
141
+ - `{name}.ttf` — TrueType font
142
+ - `{name}.woff` — WOFF (zlib)
143
+ - `{name}.woff2` — WOFF2 (brotli)
144
+ - `{name}.eot` — EOT (IE11)
145
+ - `{name}.svg` — SVG font
146
+ - `{name}.css` — Stylesheet with `@font-face`
147
+ - `{name}.js` — SVG sprite auto-injector
148
+ - `{name}.symbol.svg` — SVG sprite
149
+ - `{name}.json` — Glyph metadata
150
+ - `demo.html` / `demo.css` — Interactive preview
151
+
152
+ A ZIP archive is also written at `{dist}/{fontName}.zip`.
153
+
154
+ ## License
155
+
156
+ MIT © [Jayson Wu](https://github.com/jaysonwu991)
@@ -0,0 +1,26 @@
1
+ import { createRequire } from "node:module";
2
+ //#region \0rolldown/runtime.js
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
12
+ key = keys[i];
13
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
14
+ get: ((k) => from[k]).bind(null, key),
15
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
16
+ });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
21
+ value: mod,
22
+ enumerable: true
23
+ }) : target, mod));
24
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
25
+ //#endregion
26
+ export { __require as n, __toESM as r, __commonJSMin as t };
@@ -0,0 +1,31 @@
1
+ import { r as __toESM } from "./chunk-DnnnRqeS.mjs";
2
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { glob } from "glob";
5
+ //#region src/index.esm.mts
6
+ var wasmModule = await import("./svg2font_wasm-Dq-StF7S.mjs").then((m) => /* @__PURE__ */ __toESM(m.default, 1));
7
+ async function generate(opts) {
8
+ const svgFiles = await glob(opts.src, { absolute: true });
9
+ if (svgFiles.length === 0) throw new Error(`@jayson991/svg2font: no SVG files found matching pattern "${opts.src}"`);
10
+ const icons = await Promise.all(svgFiles.map(async (filePath) => ({
11
+ name: path.basename(filePath, ".svg"),
12
+ content: await readFile(filePath, "utf-8")
13
+ })));
14
+ const result = wasmModule.generateFromSvgs(JSON.stringify(icons), JSON.stringify({
15
+ fontName: opts.fontName,
16
+ prefix: opts.prefix ?? "icon",
17
+ startCodepoint: opts.startCodepoint ?? 57345
18
+ }));
19
+ const fontDir = path.join(opts.dist, opts.fontName);
20
+ await mkdir(fontDir, { recursive: true });
21
+ const zipName = `${opts.fontName}.zip`;
22
+ const zipPath = path.join(opts.dist, zipName);
23
+ for (const [name, bytes] of Object.entries(result.files)) if (name === zipName) await writeFile(zipPath, bytes);
24
+ else await writeFile(path.join(fontDir, name), bytes);
25
+ return {
26
+ glyphs: result.glyphs,
27
+ zipPath
28
+ };
29
+ }
30
+ //#endregion
31
+ export { generate };
package/dist/index.js ADDED
@@ -0,0 +1,54 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region \0rolldown/runtime.js
3
+ var __create = Object.create;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
6
+ var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getProtoOf = Object.getPrototypeOf;
8
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
13
+ get: ((k) => from[k]).bind(null, key),
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
20
+ value: mod,
21
+ enumerable: true
22
+ }) : target, mod));
23
+ //#endregion
24
+ let node_fs_promises = require("node:fs/promises");
25
+ let node_path = require("node:path");
26
+ node_path = __toESM(node_path);
27
+ let glob = require("glob");
28
+ //#region src/index.ts
29
+ var wasm = require(node_path.default.join(__dirname, "../wasm/svg2font_wasm.js"));
30
+ async function generate(opts) {
31
+ const svgFiles = await (0, glob.glob)(opts.src, { absolute: true });
32
+ if (svgFiles.length === 0) throw new Error(`@jayson991/svg2font: no SVG files found matching pattern "${opts.src}"`);
33
+ const icons = await Promise.all(svgFiles.map(async (filePath) => ({
34
+ name: node_path.default.basename(filePath, ".svg"),
35
+ content: await (0, node_fs_promises.readFile)(filePath, "utf-8")
36
+ })));
37
+ const result = wasm.generateFromSvgs(JSON.stringify(icons), JSON.stringify({
38
+ fontName: opts.fontName,
39
+ prefix: opts.prefix ?? "icon",
40
+ startCodepoint: opts.startCodepoint ?? 57345
41
+ }));
42
+ const fontDir = node_path.default.join(opts.dist, opts.fontName);
43
+ await (0, node_fs_promises.mkdir)(fontDir, { recursive: true });
44
+ const zipName = `${opts.fontName}.zip`;
45
+ const zipPath = node_path.default.join(opts.dist, zipName);
46
+ for (const [name, bytes] of Object.entries(result.files)) if (name === zipName) await (0, node_fs_promises.writeFile)(zipPath, bytes);
47
+ else await (0, node_fs_promises.writeFile)(node_path.default.join(fontDir, name), bytes);
48
+ return {
49
+ glyphs: result.glyphs,
50
+ zipPath
51
+ };
52
+ }
53
+ //#endregion
54
+ exports.generate = generate;
@@ -0,0 +1,174 @@
1
+ import { n as __require, t as __commonJSMin } from "./chunk-DnnnRqeS.mjs";
2
+ //#region wasm/svg2font_wasm.js
3
+ var require_svg2font_wasm = /* @__PURE__ */ __commonJSMin(((exports) => {
4
+ /**
5
+ * Generate icon font from an array of SVG icons.
6
+ *
7
+ * `icons_json` — JSON array of `{name: string, content: string}` objects.
8
+ * `opts_json` — JSON object `{fontName, prefix?, startCodepoint?}`.
9
+ *
10
+ * Returns a JS object `{glyphs, files}` where `files` maps filenames to `Uint8Array`.
11
+ * @param {string} icons_json
12
+ * @param {string} opts_json
13
+ * @returns {any}
14
+ */
15
+ function generateFromSvgs(icons_json, opts_json) {
16
+ try {
17
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
18
+ const ptr0 = passStringToWasm0(icons_json, wasm.__wbindgen_export, wasm.__wbindgen_export2);
19
+ const len0 = WASM_VECTOR_LEN;
20
+ const ptr1 = passStringToWasm0(opts_json, wasm.__wbindgen_export, wasm.__wbindgen_export2);
21
+ const len1 = WASM_VECTOR_LEN;
22
+ wasm.generateFromSvgs(retptr, ptr0, len0, ptr1, len1);
23
+ var r0 = getDataViewMemory0().getInt32(retptr + 0, true);
24
+ var r1 = getDataViewMemory0().getInt32(retptr + 4, true);
25
+ if (getDataViewMemory0().getInt32(retptr + 8, true)) throw takeObject(r1);
26
+ return takeObject(r0);
27
+ } finally {
28
+ wasm.__wbindgen_add_to_stack_pointer(16);
29
+ }
30
+ }
31
+ exports.generateFromSvgs = generateFromSvgs;
32
+ function __wbg_get_imports() {
33
+ return {
34
+ __proto__: null,
35
+ "./svg2font_wasm_bg.js": {
36
+ __proto__: null,
37
+ __wbg_Error_fdd633d4bb5dd76a: function(arg0, arg1) {
38
+ return addHeapObject(Error(getStringFromWasm0(arg0, arg1)));
39
+ },
40
+ __wbg_String_8564e559799eccda: function(arg0, arg1) {
41
+ const ptr1 = passStringToWasm0(String(getObject(arg1)), wasm.__wbindgen_export, wasm.__wbindgen_export2);
42
+ const len1 = WASM_VECTOR_LEN;
43
+ getDataViewMemory0().setInt32(arg0 + 4, len1, true);
44
+ getDataViewMemory0().setInt32(arg0 + 0, ptr1, true);
45
+ },
46
+ __wbg___wbindgen_is_string_1fca8072260dd261: function(arg0) {
47
+ return typeof getObject(arg0) === "string";
48
+ },
49
+ __wbg___wbindgen_throw_ea4887a5f8f9a9db: function(arg0, arg1) {
50
+ throw new Error(getStringFromWasm0(arg0, arg1));
51
+ },
52
+ __wbg_new_2e117a478906f062: function() {
53
+ return addHeapObject(/* @__PURE__ */ new Object());
54
+ },
55
+ __wbg_new_3444eb7412549f0b: function() {
56
+ return addHeapObject(/* @__PURE__ */ new Map());
57
+ },
58
+ __wbg_new_36e147a8ced3c6e0: function() {
59
+ return addHeapObject(new Array());
60
+ },
61
+ __wbg_set_6be42768c690e380: function(arg0, arg1, arg2) {
62
+ getObject(arg0)[takeObject(arg1)] = takeObject(arg2);
63
+ },
64
+ __wbg_set_9a1d61e17de7054c: function(arg0, arg1, arg2) {
65
+ return addHeapObject(getObject(arg0).set(getObject(arg1), getObject(arg2)));
66
+ },
67
+ __wbg_set_dc601f4a69da0bc2: function(arg0, arg1, arg2) {
68
+ getObject(arg0)[arg1 >>> 0] = takeObject(arg2);
69
+ },
70
+ __wbindgen_cast_0000000000000001: function(arg0) {
71
+ return addHeapObject(arg0);
72
+ },
73
+ __wbindgen_cast_0000000000000002: function(arg0, arg1) {
74
+ return addHeapObject(getStringFromWasm0(arg0, arg1));
75
+ },
76
+ __wbindgen_object_clone_ref: function(arg0) {
77
+ return addHeapObject(getObject(arg0));
78
+ },
79
+ __wbindgen_object_drop_ref: function(arg0) {
80
+ takeObject(arg0);
81
+ }
82
+ }
83
+ };
84
+ }
85
+ function addHeapObject(obj) {
86
+ if (heap_next === heap.length) heap.push(heap.length + 1);
87
+ const idx = heap_next;
88
+ heap_next = heap[idx];
89
+ heap[idx] = obj;
90
+ return idx;
91
+ }
92
+ function dropObject(idx) {
93
+ if (idx < 1028) return;
94
+ heap[idx] = heap_next;
95
+ heap_next = idx;
96
+ }
97
+ var cachedDataViewMemory0 = null;
98
+ function getDataViewMemory0() {
99
+ if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || cachedDataViewMemory0.buffer.detached === void 0 && cachedDataViewMemory0.buffer !== wasm.memory.buffer) cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
100
+ return cachedDataViewMemory0;
101
+ }
102
+ function getStringFromWasm0(ptr, len) {
103
+ return decodeText(ptr >>> 0, len);
104
+ }
105
+ var cachedUint8ArrayMemory0 = null;
106
+ function getUint8ArrayMemory0() {
107
+ if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
108
+ return cachedUint8ArrayMemory0;
109
+ }
110
+ function getObject(idx) {
111
+ return heap[idx];
112
+ }
113
+ var heap = new Array(1024).fill(void 0);
114
+ heap.push(void 0, null, true, false);
115
+ var heap_next = heap.length;
116
+ function passStringToWasm0(arg, malloc, realloc) {
117
+ if (realloc === void 0) {
118
+ const buf = cachedTextEncoder.encode(arg);
119
+ const ptr = malloc(buf.length, 1) >>> 0;
120
+ getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
121
+ WASM_VECTOR_LEN = buf.length;
122
+ return ptr;
123
+ }
124
+ let len = arg.length;
125
+ let ptr = malloc(len, 1) >>> 0;
126
+ const mem = getUint8ArrayMemory0();
127
+ let offset = 0;
128
+ for (; offset < len; offset++) {
129
+ const code = arg.charCodeAt(offset);
130
+ if (code > 127) break;
131
+ mem[ptr + offset] = code;
132
+ }
133
+ if (offset !== len) {
134
+ if (offset !== 0) arg = arg.slice(offset);
135
+ ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
136
+ const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
137
+ const ret = cachedTextEncoder.encodeInto(arg, view);
138
+ offset += ret.written;
139
+ ptr = realloc(ptr, len, offset, 1) >>> 0;
140
+ }
141
+ WASM_VECTOR_LEN = offset;
142
+ return ptr;
143
+ }
144
+ function takeObject(idx) {
145
+ const ret = getObject(idx);
146
+ dropObject(idx);
147
+ return ret;
148
+ }
149
+ var cachedTextDecoder = new TextDecoder("utf-8", {
150
+ ignoreBOM: true,
151
+ fatal: true
152
+ });
153
+ cachedTextDecoder.decode();
154
+ function decodeText(ptr, len) {
155
+ return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
156
+ }
157
+ var cachedTextEncoder = new TextEncoder();
158
+ if (!("encodeInto" in cachedTextEncoder)) cachedTextEncoder.encodeInto = function(arg, view) {
159
+ const buf = cachedTextEncoder.encode(arg);
160
+ view.set(buf);
161
+ return {
162
+ read: arg.length,
163
+ written: buf.length
164
+ };
165
+ };
166
+ var WASM_VECTOR_LEN = 0;
167
+ var wasmPath = `${__dirname}/svg2font_wasm_bg.wasm`;
168
+ var wasmBytes = __require("fs").readFileSync(wasmPath);
169
+ var wasmModule = new WebAssembly.Module(wasmBytes);
170
+ var wasm = new WebAssembly.Instance(wasmModule, __wbg_get_imports()).exports;
171
+ }));
172
+ //#endregion
173
+ export default require_svg2font_wasm();
174
+ export {};
package/index.d.ts ADDED
@@ -0,0 +1,48 @@
1
+ export interface GenerateOptions {
2
+ /** Glob pattern for source SVG files (e.g. "icons/**\/*.svg") */
3
+ src: string;
4
+ /** Output directory for generated files */
5
+ dist: string;
6
+ /** Font family name used for file names and CSS (e.g. "myicons") */
7
+ fontName: string;
8
+ /** CSS class prefix (default: "icon") */
9
+ prefix?: string;
10
+ /** Starting Unicode codepoint as a decimal number (default: 0xe001 = 57345) */
11
+ startCodepoint?: number;
12
+ }
13
+
14
+ export interface GlyphMeta {
15
+ /** Icon name in kebab-case (e.g. "arrow-right") */
16
+ name: string;
17
+ /** Assigned Unicode codepoint (e.g. 57345 for U+E001) */
18
+ codepoint: number;
19
+ /** HTML entity string (e.g. "&#xe001;") */
20
+ unicode: string;
21
+ /** Full CSS class name (e.g. "icon-arrow-right") */
22
+ className: string;
23
+ }
24
+
25
+ export interface GenerateResult {
26
+ /** Metadata for every generated icon glyph */
27
+ glyphs: GlyphMeta[];
28
+ /** Absolute path to the generated ZIP archive */
29
+ zipPath: string;
30
+ }
31
+
32
+ /**
33
+ * Generate an iconfont bundle from a set of SVG files.
34
+ *
35
+ * @example
36
+ * ```ts
37
+ * import { generate } from '@jayson991/svg2font';
38
+ *
39
+ * const result = await generate({
40
+ * src: 'icons\/**\/*.svg',
41
+ * dist: 'dist',
42
+ * fontName: 'myicons',
43
+ * });
44
+ *
45
+ * console.log(`Generated ${result.glyphs.length} icons → ${result.zipPath}`);
46
+ * ```
47
+ */
48
+ export function generate(options: GenerateOptions): Promise<GenerateResult>;
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@jayson991/svg2font",
3
+ "version": "1.0.0",
4
+ "description": "Generate icon fonts from SVG files — TypeScript/WASM library",
5
+ "main": "dist/index.cjs",
6
+ "module": "dist/index.esm.mjs",
7
+ "types": "index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.esm.mjs",
11
+ "require": "./dist/index.cjs",
12
+ "types": "./index.d.ts"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist/",
17
+ "wasm/",
18
+ "index.d.ts"
19
+ ],
20
+ "engines": {
21
+ "node": ">=18"
22
+ },
23
+ "scripts": {
24
+ "build": "vite build && vite build --config vite.esm.config.mts",
25
+ "typecheck": "tsc"
26
+ },
27
+ "dependencies": {
28
+ "glob": "^11.0.0"
29
+ },
30
+ "devDependencies": {
31
+ "@types/node": "^24.0.0",
32
+ "typescript": "^5.0.0",
33
+ "vite": "^8.0.16"
34
+ },
35
+ "license": "MIT",
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "https://github.com/jaysonwu991/svg2font"
39
+ },
40
+ "homepage": "https://github.com/jaysonwu991/svg2font/tree/main/packages/svg2font",
41
+ "bugs": {
42
+ "url": "https://github.com/jaysonwu991/svg2font/issues"
43
+ }
44
+ }
package/wasm/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2025 Jayson Wu
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package/wasm/README.md ADDED
@@ -0,0 +1,66 @@
1
+ # svg2font
2
+
3
+ > Convert SVG icon sets into complete iconfont bundles (TTF/WOFF/WOFF2/EOT/SVG) with CSS, demos, and sprites
4
+
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
6
+
7
+ A monorepo containing two packages:
8
+
9
+ | Package | Description |
10
+ |---------|-------------|
11
+ | [`@jayson991/svg2font-cli`](packages/svg2font-cli) | CLI tool — `svg2font` command |
12
+ | [`@jayson991/svg2font`](packages/svg2font) | TypeScript/WASM library for programmatic use |
13
+
14
+ ## Packages
15
+
16
+ ### [@jayson991/svg2font-cli](packages/svg2font-cli/README.md)
17
+
18
+ Install globally and run from the command line:
19
+
20
+ ```bash
21
+ npm install -g @jayson991/svg2font-cli
22
+ svg2font --src "icons/**/*.svg" --dist dist --font-name myicons
23
+ ```
24
+
25
+ ### [@jayson991/svg2font](packages/svg2font/README.md)
26
+
27
+ Import as a Node.js module:
28
+
29
+ ```typescript
30
+ import { generate } from '@jayson991/svg2font';
31
+
32
+ const result = await generate({
33
+ src: 'icons/**/*.svg',
34
+ dist: 'dist',
35
+ fontName: 'myicons',
36
+ });
37
+
38
+ console.log(`Generated ${result.glyphs.length} icons → ${result.zipPath}`);
39
+ ```
40
+
41
+ ## Development
42
+
43
+ ```bash
44
+ # Clone
45
+ git clone https://github.com/jaysonwu991/svg2font.git
46
+ cd svg2font
47
+
48
+ # Build CLI binary
49
+ cargo build --release
50
+
51
+ # Build WASM module
52
+ cargo build --release --features wasm
53
+
54
+ # Run tests
55
+ cargo test
56
+
57
+ # Lint (native targets)
58
+ cargo clippy --all-targets -- -D warnings
59
+
60
+ # Check WASM feature compiles
61
+ cargo check --lib --features wasm --no-default-features --target wasm32-unknown-unknown
62
+ ```
63
+
64
+ ## License
65
+
66
+ MIT © [Jayson Wu](https://github.com/jaysonwu991)
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "svg2font",
3
+ "collaborators": [
4
+ "svg2font contributors"
5
+ ],
6
+ "description": "SVG to icon font converter with comprehensive format support",
7
+ "version": "1.0.0",
8
+ "license": "MIT",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/jaysonwu991/svg2font"
12
+ },
13
+ "files": [
14
+ "svg2font_wasm_bg.wasm",
15
+ "svg2font_wasm.js",
16
+ "svg2font_wasm.d.ts"
17
+ ],
18
+ "main": "svg2font_wasm.js",
19
+ "types": "svg2font_wasm.d.ts",
20
+ "keywords": [
21
+ "svg",
22
+ "font",
23
+ "icon",
24
+ "ttf",
25
+ "woff"
26
+ ]
27
+ }
@@ -0,0 +1,12 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+
4
+ /**
5
+ * Generate icon font from an array of SVG icons.
6
+ *
7
+ * `icons_json` — JSON array of `{name: string, content: string}` objects.
8
+ * `opts_json` — JSON object `{fontName, prefix?, startCodepoint?}`.
9
+ *
10
+ * Returns a JS object `{glyphs, files}` where `files` maps filenames to `Uint8Array`.
11
+ */
12
+ export function generateFromSvgs(icons_json: string, opts_json: string): any;
@@ -0,0 +1,211 @@
1
+ /* @ts-self-types="./svg2font_wasm.d.ts" */
2
+
3
+ /**
4
+ * Generate icon font from an array of SVG icons.
5
+ *
6
+ * `icons_json` — JSON array of `{name: string, content: string}` objects.
7
+ * `opts_json` — JSON object `{fontName, prefix?, startCodepoint?}`.
8
+ *
9
+ * Returns a JS object `{glyphs, files}` where `files` maps filenames to `Uint8Array`.
10
+ * @param {string} icons_json
11
+ * @param {string} opts_json
12
+ * @returns {any}
13
+ */
14
+ function generateFromSvgs(icons_json, opts_json) {
15
+ try {
16
+ const retptr = wasm.__wbindgen_add_to_stack_pointer(-16);
17
+ const ptr0 = passStringToWasm0(icons_json, wasm.__wbindgen_export, wasm.__wbindgen_export2);
18
+ const len0 = WASM_VECTOR_LEN;
19
+ const ptr1 = passStringToWasm0(opts_json, wasm.__wbindgen_export, wasm.__wbindgen_export2);
20
+ const len1 = WASM_VECTOR_LEN;
21
+ wasm.generateFromSvgs(retptr, ptr0, len0, ptr1, len1);
22
+ var r0 = getDataViewMemory0().getInt32(retptr + 4 * 0, true);
23
+ var r1 = getDataViewMemory0().getInt32(retptr + 4 * 1, true);
24
+ var r2 = getDataViewMemory0().getInt32(retptr + 4 * 2, true);
25
+ if (r2) {
26
+ throw takeObject(r1);
27
+ }
28
+ return takeObject(r0);
29
+ } finally {
30
+ wasm.__wbindgen_add_to_stack_pointer(16);
31
+ }
32
+ }
33
+ exports.generateFromSvgs = generateFromSvgs;
34
+ function __wbg_get_imports() {
35
+ const import0 = {
36
+ __proto__: null,
37
+ __wbg_Error_fdd633d4bb5dd76a: function(arg0, arg1) {
38
+ const ret = Error(getStringFromWasm0(arg0, arg1));
39
+ return addHeapObject(ret);
40
+ },
41
+ __wbg_String_8564e559799eccda: function(arg0, arg1) {
42
+ const ret = String(getObject(arg1));
43
+ const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_export, wasm.__wbindgen_export2);
44
+ const len1 = WASM_VECTOR_LEN;
45
+ getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
46
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
47
+ },
48
+ __wbg___wbindgen_is_string_1fca8072260dd261: function(arg0) {
49
+ const ret = typeof(getObject(arg0)) === 'string';
50
+ return ret;
51
+ },
52
+ __wbg___wbindgen_throw_ea4887a5f8f9a9db: function(arg0, arg1) {
53
+ throw new Error(getStringFromWasm0(arg0, arg1));
54
+ },
55
+ __wbg_new_2e117a478906f062: function() {
56
+ const ret = new Object();
57
+ return addHeapObject(ret);
58
+ },
59
+ __wbg_new_3444eb7412549f0b: function() {
60
+ const ret = new Map();
61
+ return addHeapObject(ret);
62
+ },
63
+ __wbg_new_36e147a8ced3c6e0: function() {
64
+ const ret = new Array();
65
+ return addHeapObject(ret);
66
+ },
67
+ __wbg_set_6be42768c690e380: function(arg0, arg1, arg2) {
68
+ getObject(arg0)[takeObject(arg1)] = takeObject(arg2);
69
+ },
70
+ __wbg_set_9a1d61e17de7054c: function(arg0, arg1, arg2) {
71
+ const ret = getObject(arg0).set(getObject(arg1), getObject(arg2));
72
+ return addHeapObject(ret);
73
+ },
74
+ __wbg_set_dc601f4a69da0bc2: function(arg0, arg1, arg2) {
75
+ getObject(arg0)[arg1 >>> 0] = takeObject(arg2);
76
+ },
77
+ __wbindgen_cast_0000000000000001: function(arg0) {
78
+ // Cast intrinsic for `F64 -> Externref`.
79
+ const ret = arg0;
80
+ return addHeapObject(ret);
81
+ },
82
+ __wbindgen_cast_0000000000000002: function(arg0, arg1) {
83
+ // Cast intrinsic for `Ref(String) -> Externref`.
84
+ const ret = getStringFromWasm0(arg0, arg1);
85
+ return addHeapObject(ret);
86
+ },
87
+ __wbindgen_object_clone_ref: function(arg0) {
88
+ const ret = getObject(arg0);
89
+ return addHeapObject(ret);
90
+ },
91
+ __wbindgen_object_drop_ref: function(arg0) {
92
+ takeObject(arg0);
93
+ },
94
+ };
95
+ return {
96
+ __proto__: null,
97
+ "./svg2font_wasm_bg.js": import0,
98
+ };
99
+ }
100
+
101
+ function addHeapObject(obj) {
102
+ if (heap_next === heap.length) heap.push(heap.length + 1);
103
+ const idx = heap_next;
104
+ heap_next = heap[idx];
105
+
106
+ heap[idx] = obj;
107
+ return idx;
108
+ }
109
+
110
+ function dropObject(idx) {
111
+ if (idx < 1028) return;
112
+ heap[idx] = heap_next;
113
+ heap_next = idx;
114
+ }
115
+
116
+ let cachedDataViewMemory0 = null;
117
+ function getDataViewMemory0() {
118
+ if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {
119
+ cachedDataViewMemory0 = new DataView(wasm.memory.buffer);
120
+ }
121
+ return cachedDataViewMemory0;
122
+ }
123
+
124
+ function getStringFromWasm0(ptr, len) {
125
+ return decodeText(ptr >>> 0, len);
126
+ }
127
+
128
+ let cachedUint8ArrayMemory0 = null;
129
+ function getUint8ArrayMemory0() {
130
+ if (cachedUint8ArrayMemory0 === null || cachedUint8ArrayMemory0.byteLength === 0) {
131
+ cachedUint8ArrayMemory0 = new Uint8Array(wasm.memory.buffer);
132
+ }
133
+ return cachedUint8ArrayMemory0;
134
+ }
135
+
136
+ function getObject(idx) { return heap[idx]; }
137
+
138
+ let heap = new Array(1024).fill(undefined);
139
+ heap.push(undefined, null, true, false);
140
+
141
+ let heap_next = heap.length;
142
+
143
+ function passStringToWasm0(arg, malloc, realloc) {
144
+ if (realloc === undefined) {
145
+ const buf = cachedTextEncoder.encode(arg);
146
+ const ptr = malloc(buf.length, 1) >>> 0;
147
+ getUint8ArrayMemory0().subarray(ptr, ptr + buf.length).set(buf);
148
+ WASM_VECTOR_LEN = buf.length;
149
+ return ptr;
150
+ }
151
+
152
+ let len = arg.length;
153
+ let ptr = malloc(len, 1) >>> 0;
154
+
155
+ const mem = getUint8ArrayMemory0();
156
+
157
+ let offset = 0;
158
+
159
+ for (; offset < len; offset++) {
160
+ const code = arg.charCodeAt(offset);
161
+ if (code > 0x7F) break;
162
+ mem[ptr + offset] = code;
163
+ }
164
+ if (offset !== len) {
165
+ if (offset !== 0) {
166
+ arg = arg.slice(offset);
167
+ }
168
+ ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0;
169
+ const view = getUint8ArrayMemory0().subarray(ptr + offset, ptr + len);
170
+ const ret = cachedTextEncoder.encodeInto(arg, view);
171
+
172
+ offset += ret.written;
173
+ ptr = realloc(ptr, len, offset, 1) >>> 0;
174
+ }
175
+
176
+ WASM_VECTOR_LEN = offset;
177
+ return ptr;
178
+ }
179
+
180
+ function takeObject(idx) {
181
+ const ret = getObject(idx);
182
+ dropObject(idx);
183
+ return ret;
184
+ }
185
+
186
+ let cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true });
187
+ cachedTextDecoder.decode();
188
+ function decodeText(ptr, len) {
189
+ return cachedTextDecoder.decode(getUint8ArrayMemory0().subarray(ptr, ptr + len));
190
+ }
191
+
192
+ const cachedTextEncoder = new TextEncoder();
193
+
194
+ if (!('encodeInto' in cachedTextEncoder)) {
195
+ cachedTextEncoder.encodeInto = function (arg, view) {
196
+ const buf = cachedTextEncoder.encode(arg);
197
+ view.set(buf);
198
+ return {
199
+ read: arg.length,
200
+ written: buf.length
201
+ };
202
+ };
203
+ }
204
+
205
+ let WASM_VECTOR_LEN = 0;
206
+
207
+ const wasmPath = `${__dirname}/svg2font_wasm_bg.wasm`;
208
+ const wasmBytes = require('fs').readFileSync(wasmPath);
209
+ const wasmModule = new WebAssembly.Module(wasmBytes);
210
+ let wasmInstance = new WebAssembly.Instance(wasmModule, __wbg_get_imports());
211
+ let wasm = wasmInstance.exports;
Binary file
@@ -0,0 +1,7 @@
1
+ /* tslint:disable */
2
+ /* eslint-disable */
3
+ export const memory: WebAssembly.Memory;
4
+ export const generateFromSvgs: (a: number, b: number, c: number, d: number, e: number) => void;
5
+ export const __wbindgen_export: (a: number, b: number) => number;
6
+ export const __wbindgen_export2: (a: number, b: number, c: number, d: number) => number;
7
+ export const __wbindgen_add_to_stack_pointer: (a: number) => number;