unplugin-cheetah-grid-icon-svg 0.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,115 @@
1
+ # unplugin-cheetah-grid-icon-svg
2
+
3
+ Unplugin that loads the icon module for Cheetah Grid from SVG.
4
+
5
+ This package is the Vite-friendly replacement for `cheetah-grid-icon-svg-loader`.
6
+ It uses the same SVG-to-icon conversion logic and also exposes Rollup, Rolldown,
7
+ Webpack, Rspack, and esbuild adapters through `unplugin`.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install --save-dev unplugin-cheetah-grid-icon-svg
13
+ ```
14
+
15
+ ## Usage with Vite
16
+
17
+ ```js
18
+ import cheetahGridIconSvg from "unplugin-cheetah-grid-icon-svg/vite";
19
+
20
+ export default {
21
+ plugins: [
22
+ cheetahGridIconSvg(),
23
+ ],
24
+ };
25
+ ```
26
+
27
+ ```js
28
+ import gridOn from "material-design-icons/image/svg/production/ic_grid_on_24px.svg?cheetah-grid-icon";
29
+
30
+ const icons = {
31
+ gridOn,
32
+ };
33
+
34
+ cheetahGrid.register.icons(icons);
35
+ ```
36
+
37
+ ## Transform a Set of SVG Files
38
+
39
+ If you want imports from a known icon directory to behave like the old webpack
40
+ loader without adding a query to every import, pass `include`.
41
+
42
+ ```js
43
+ import cheetahGridIconSvg from "unplugin-cheetah-grid-icon-svg/vite";
44
+
45
+ export default {
46
+ plugins: [
47
+ cheetahGridIconSvg({
48
+ include: /material-design-icons\/.+\.svg$/,
49
+ }),
50
+ ],
51
+ };
52
+ ```
53
+
54
+ ## Font SVG
55
+
56
+ Font SVG files are converted to an object whose keys are glyph unicode values,
57
+ matching `cheetah-grid-icon-svg-loader`.
58
+
59
+ ```js
60
+ import materialIcons from "material-design-icons/iconfont/MaterialIcons-Regular.svg?cheetah-grid-icon";
61
+ ```
62
+
63
+ You can also load a single glyph.
64
+
65
+ ```js
66
+ import add from "material-design-icons/iconfont/MaterialIcons-Regular.svg?cheetah-grid-icon&glyph-name=add";
67
+ ```
68
+
69
+ ## Other Bundlers
70
+
71
+ ```js
72
+ const cheetahGridIconSvg = require("unplugin-cheetah-grid-icon-svg/webpack");
73
+
74
+ module.exports = {
75
+ plugins: [
76
+ cheetahGridIconSvg(),
77
+ ],
78
+ };
79
+ ```
80
+
81
+ ```js
82
+ import cheetahGridIconSvg from "unplugin-cheetah-grid-icon-svg/rollup";
83
+
84
+ export default {
85
+ plugins: [
86
+ cheetahGridIconSvg(),
87
+ ],
88
+ };
89
+ ```
90
+
91
+ ```js
92
+ import cheetahGridIconSvg from "unplugin-cheetah-grid-icon-svg/rolldown";
93
+
94
+ export default {
95
+ plugins: [
96
+ cheetahGridIconSvg(),
97
+ ],
98
+ };
99
+ ```
100
+
101
+ ## Options
102
+
103
+ ```ts
104
+ interface Options {
105
+ include?: string | RegExp | ((id: string) => boolean) | Array<string | RegExp | ((id: string) => boolean)>;
106
+ exclude?: string | RegExp | ((id: string) => boolean) | Array<string | RegExp | ((id: string) => boolean)>;
107
+ query?: string | string[] | false;
108
+ }
109
+ ```
110
+
111
+ - `include` transforms matching SVG imports without requiring a query.
112
+ - `exclude` prevents matching SVG imports from being transformed.
113
+ - `query` changes the query names that opt in to transformation. The default is
114
+ `["cheetah-grid-icon", "cg-icon"]`. Set `query: false` to transform every
115
+ SVG matched by `include`, or every SVG import when `include` is omitted.
@@ -0,0 +1,4 @@
1
+ //#region src/esbuild.ts
2
+ var esbuild_default = require("./src.cjs").unplugin.esbuild;
3
+ //#endregion
4
+ module.exports = esbuild_default;
@@ -0,0 +1,6 @@
1
+ import { r as Options } from "./index.mjs";
2
+
3
+ //#region src/esbuild.d.ts
4
+ declare const _default: (options?: Options | undefined) => EsbuildPlugin;
5
+ //#endregion
6
+ export { _default as default };
@@ -0,0 +1,5 @@
1
+ import { t as unplugin } from "./src.mjs";
2
+ //#region src/esbuild.ts
3
+ var esbuild_default = unplugin.esbuild;
4
+ //#endregion
5
+ export { esbuild_default as default };
package/dist/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ const require_src = require("./src.cjs");
2
+ module.exports = require_src.unplugin;
@@ -0,0 +1,14 @@
1
+ import * as unplugin0 from "unplugin";
2
+
3
+ //#region src/core/transform.d.ts
4
+ type FilterPattern = string | RegExp | ((id: string) => boolean) | FilterPattern[];
5
+ interface Options {
6
+ include?: FilterPattern;
7
+ exclude?: FilterPattern;
8
+ query?: string | string[] | false;
9
+ }
10
+ //#endregion
11
+ //#region src/index.d.ts
12
+ declare const unplugin: unplugin0.UnpluginInstance<Options | undefined, boolean>;
13
+ //#endregion
14
+ export { FilterPattern as n, Options as r, unplugin as t };
package/dist/index.mjs ADDED
@@ -0,0 +1,2 @@
1
+ import { t as unplugin } from "./src.mjs";
2
+ export { unplugin as default };
@@ -0,0 +1,2 @@
1
+ import { n as FilterPattern, r as Options, t as unplugin } from "./index.mjs";
2
+ export { FilterPattern, Options, unplugin as default };
@@ -0,0 +1,4 @@
1
+ //#region src/rolldown.ts
2
+ var rolldown_default = require("./src.cjs").unplugin.rolldown;
3
+ //#endregion
4
+ module.exports = rolldown_default;
@@ -0,0 +1,7 @@
1
+ import { r as Options } from "./index.mjs";
2
+ import * as rolldown0 from "rolldown";
3
+
4
+ //#region src/rolldown.d.ts
5
+ declare const _default: (options?: Options | undefined) => rolldown0.Plugin<any> | rolldown0.Plugin<any>[];
6
+ //#endregion
7
+ export { _default as default };
@@ -0,0 +1,5 @@
1
+ import { t as unplugin } from "./src.mjs";
2
+ //#region src/rolldown.ts
3
+ var rolldown_default = unplugin.rolldown;
4
+ //#endregion
5
+ export { rolldown_default as default };
@@ -0,0 +1,4 @@
1
+ //#region src/rollup.ts
2
+ var rollup_default = require("./src.cjs").unplugin.rollup;
3
+ //#endregion
4
+ module.exports = rollup_default;
@@ -0,0 +1,6 @@
1
+ import { r as Options } from "./index.mjs";
2
+
3
+ //#region src/rollup.d.ts
4
+ declare const _default: (options?: Options | undefined) => any;
5
+ //#endregion
6
+ export { _default as default };
@@ -0,0 +1,5 @@
1
+ import { t as unplugin } from "./src.mjs";
2
+ //#region src/rollup.ts
3
+ var rollup_default = unplugin.rollup;
4
+ //#endregion
5
+ export { rollup_default as default };
@@ -0,0 +1,4 @@
1
+ //#region src/rspack.ts
2
+ var rspack_default = require("./src.cjs").unplugin.rspack;
3
+ //#endregion
4
+ module.exports = rspack_default;
@@ -0,0 +1,6 @@
1
+ import { r as Options } from "./index.mjs";
2
+
3
+ //#region src/rspack.d.ts
4
+ declare const _default: (options?: Options | undefined) => RspackPluginInstance;
5
+ //#endregion
6
+ export { _default as default };
@@ -0,0 +1,5 @@
1
+ import { t as unplugin } from "./src.mjs";
2
+ //#region src/rspack.ts
3
+ var rspack_default = unplugin.rspack;
4
+ //#endregion
5
+ export { rspack_default as default };
package/dist/src.cjs ADDED
@@ -0,0 +1,374 @@
1
+ let unplugin = require("unplugin");
2
+ let node_module = require("node:module");
3
+ let _xmldom_xmldom = require("@xmldom/xmldom");
4
+ //#region src/core/svg-data.ts
5
+ const ELEMENT_NODE = 1;
6
+ const parser = new (typeof window !== "undefined" && window.DOMParser ? window.DOMParser : _xmldom_xmldom.DOMParser)();
7
+ function isElementNode(node) {
8
+ return node.nodeType === ELEMENT_NODE && typeof node.tagName === "string";
9
+ }
10
+ function findElement(el, test) {
11
+ const { childNodes } = el;
12
+ for (let i = 0; i < childNodes.length; i++) {
13
+ const child = childNodes[i];
14
+ if (!isElementNode(child)) continue;
15
+ if (test(child)) return child;
16
+ const result = findElement(child, test);
17
+ if (result) return result;
18
+ }
19
+ return null;
20
+ }
21
+ var Svg = class {
22
+ constructor(svgCode) {
23
+ this.glyphs = {};
24
+ this.glyphUnicodes = {};
25
+ const document = parser.parseFromString(svgCode, "image/svg+xml");
26
+ this.svg = document.documentElement;
27
+ }
28
+ findElement(test) {
29
+ return findElement(this.svg, test);
30
+ }
31
+ get fontFaceElement() {
32
+ if (this.cachedFontFaceElement === void 0) this.cachedFontFaceElement = this.findElement((child) => child.tagName.toLowerCase() === "font-face");
33
+ return this.cachedFontFaceElement;
34
+ }
35
+ get fontElement() {
36
+ if (this.cachedFontElement === void 0) this.cachedFontElement = this.findElement((child) => child.tagName.toLowerCase() === "font");
37
+ return this.cachedFontElement;
38
+ }
39
+ findGlyph(glyphName) {
40
+ if (!(glyphName in this.glyphs)) this.glyphs[glyphName] = this.findElement((child) => child.getAttribute("glyph-name") === glyphName);
41
+ return this.glyphs[glyphName] || null;
42
+ }
43
+ findGlyphByUnicode(unicode) {
44
+ if (!(unicode in this.glyphUnicodes)) this.glyphUnicodes[unicode] = this.findElement((child) => child.getAttribute("unicode") === unicode);
45
+ return this.glyphUnicodes[unicode] || null;
46
+ }
47
+ walkAllGlyph(callback) {
48
+ const walkGlyph = (el) => {
49
+ const { childNodes } = el;
50
+ for (let i = 0; i < childNodes.length; i++) {
51
+ const child = childNodes[i];
52
+ if (!isElementNode(child)) continue;
53
+ const unicode = child.getAttribute("unicode");
54
+ if (unicode && child.getAttribute("d")) {
55
+ if (!this.glyphUnicodes[unicode]) this.glyphUnicodes[unicode] = child;
56
+ const glyphName = child.getAttribute("glyph-name");
57
+ if (glyphName && !this.glyphs[glyphName]) this.glyphs[glyphName] = child;
58
+ callback(child);
59
+ } else walkGlyph(child);
60
+ }
61
+ };
62
+ walkGlyph(this.svg);
63
+ }
64
+ };
65
+ const cache = {};
66
+ function get(svgCode) {
67
+ const cacheKey = `font:${svgCode}`;
68
+ cache[cacheKey] = cache[cacheKey] || new Svg(svgCode);
69
+ return cache[cacheKey];
70
+ }
71
+ (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href);
72
+ function attr(el, name) {
73
+ return el.getAttribute(name) || "";
74
+ }
75
+ function polygonToPath(polygon) {
76
+ return `M${attr(polygon, "points")}z`;
77
+ }
78
+ function polylineToPath(polyline) {
79
+ return `M${attr(polyline, "points")}`;
80
+ }
81
+ function circleToPath(circle) {
82
+ const cx = Number(attr(circle, "cx"));
83
+ const cy = Number(attr(circle, "cy"));
84
+ const r = Number(attr(circle, "r"));
85
+ const segments = 8;
86
+ const angle = 2 * Math.PI / segments;
87
+ const anchorX = (theta) => r * Math.cos(theta);
88
+ const anchorY = (theta) => r * Math.sin(theta);
89
+ const controlX = (theta) => anchorX(theta) + r * Math.tan(angle / 2) * Math.cos(theta - Math.PI / 2);
90
+ const controlY = (theta) => anchorY(theta) + r * Math.tan(angle / 2) * Math.sin(theta - Math.PI / 2);
91
+ let paths = `M${cx + r} ${cy}`;
92
+ for (let index = 1; index <= segments; index++) {
93
+ const theta = index * angle;
94
+ paths += `Q${controlX(theta) + cx} ${controlY(theta) + cy} ${anchorX(theta) + cx} ${anchorY(theta) + cy}`;
95
+ }
96
+ return paths;
97
+ }
98
+ function rectToPath(rect) {
99
+ const x = Number(attr(rect, "x"));
100
+ const y = Number(attr(rect, "y"));
101
+ const width = Number(attr(rect, "width"));
102
+ return `M${x},${y} h${width} v${Number(attr(rect, "height"))} h${-width}z`;
103
+ }
104
+ function getD(path) {
105
+ if (path.getAttribute("fill") === "none") return "";
106
+ return attr(path, "d").replace(/[\n\r]/gu, "");
107
+ }
108
+ function elementToPaths(el, resource) {
109
+ switch (el.tagName.toLowerCase()) {
110
+ case "path":
111
+ case "glyph": return getD(el);
112
+ case "circle": return circleToPath(el);
113
+ case "polygon": return polygonToPath(el);
114
+ case "polyline": return polylineToPath(el);
115
+ case "rect": return rectToPath(el);
116
+ case "g": {
117
+ let path = "";
118
+ const { childNodes } = el;
119
+ for (let i = 0; i < childNodes.length; i++) {
120
+ const child = childNodes[i];
121
+ if (!isElementNode(child)) continue;
122
+ if (!child.getAttribute("fill")) child.setAttribute("fill", el.getAttribute("fill"));
123
+ path += elementToPaths(child, resource);
124
+ }
125
+ return path;
126
+ }
127
+ default: console.warn(`unsupported:${el.tagName}`, `@ ${resource}\n${el.innerHTML}`);
128
+ }
129
+ return "";
130
+ }
131
+ function buildScript({ offsetX = 0, offsetY = 0, width, height, d, isGlyph, html, resource }) {
132
+ let flags = "";
133
+ if (isGlyph) flags += `ud: 1,
134
+ `;
135
+ if (offsetX !== 0) flags += `x: ${offsetX},
136
+ `;
137
+ if (offsetY !== 0) flags += `y: ${offsetY},
138
+ `;
139
+ return `{
140
+ /*
141
+ original svg
142
+ ${html}
143
+ @ ${resource}
144
+ */
145
+ d: '${d}',
146
+ width: ${width},
147
+ height: ${height},
148
+ ${flags}
149
+ }`;
150
+ }
151
+ function glyphToJSON(svgString, { glyphName, unicode }, resource) {
152
+ const svg = get(svgString);
153
+ const findGlyph = () => {
154
+ if (glyphName && glyphName !== true) return svg.findGlyph(glyphName);
155
+ return unicode && unicode !== true ? svg.findGlyphByUnicode(unicode) : null;
156
+ };
157
+ const emptyElement = { getAttribute: () => "" };
158
+ const fontFace = svg.fontFaceElement || emptyElement;
159
+ const font = svg.fontElement || emptyElement;
160
+ const glyph = findGlyph();
161
+ if (!glyph) throw new Error(`Glyph not found: ${glyphName && glyphName !== true ? glyphName : unicode && unicode !== true ? unicode : ""}`);
162
+ const fontHorizAdvX = Number(font.getAttribute("horiz-adv-x")) || 0;
163
+ const fontVertAdvX = Number(font.getAttribute("vert-adv-x")) || 0;
164
+ const horizAdvX = Number(glyph.getAttribute("horiz-adv-x")) || fontHorizAdvX || 0;
165
+ const vertAdvX = Number(glyph.getAttribute("vert-adv-x")) || fontVertAdvX || 0;
166
+ const unitsPerEm = Number(fontFace.getAttribute("units-per-em")) || 1e3;
167
+ const descent = Number(fontFace.getAttribute("descent")) || vertAdvX;
168
+ let size = unitsPerEm;
169
+ const contentSize = {
170
+ width: horizAdvX || unitsPerEm,
171
+ height: vertAdvX || unitsPerEm
172
+ };
173
+ if (horizAdvX > size) size = horizAdvX;
174
+ if (vertAdvX > size) size = vertAdvX;
175
+ let offsetX = 0;
176
+ let offsetY = -descent;
177
+ offsetX += Math.round((size - contentSize.width) / 2);
178
+ offsetY += Math.round((size - contentSize.height) / 2);
179
+ return buildScript({
180
+ offsetX,
181
+ offsetY,
182
+ width: size,
183
+ height: size,
184
+ d: elementToPaths(glyph, resource),
185
+ isGlyph: true,
186
+ html: glyph.outerHTML,
187
+ resource
188
+ });
189
+ }
190
+ function svgToJSON(svgString, resource) {
191
+ const { svg } = get(svgString);
192
+ const viewBox = attr(svg, "viewBox").split(" ");
193
+ const width = Number(attr(svg, "width") || viewBox[2]) || 0;
194
+ const height = Number(attr(svg, "height") || viewBox[3]) || 0;
195
+ const offsetX = 0 - Number(viewBox[0]) || 0;
196
+ const offsetY = 0 - Number(viewBox[1]) || 0;
197
+ let d = "";
198
+ const { childNodes } = svg;
199
+ for (let i = 0; i < childNodes.length; i++) {
200
+ const el = childNodes[i];
201
+ if (!isElementNode(el)) continue;
202
+ d += elementToPaths(el, resource);
203
+ }
204
+ return buildScript({
205
+ offsetX,
206
+ offsetY,
207
+ width,
208
+ height,
209
+ d,
210
+ html: svgString,
211
+ resource
212
+ });
213
+ }
214
+ function normalizeResource$1(resource) {
215
+ let index = resource.indexOf("\\node_modules\\");
216
+ if (index === -1) index = resource.indexOf("/node_modules/");
217
+ if (index >= 0) return resource.slice(index + 14);
218
+ return resource;
219
+ }
220
+ function sourceToIconJsObject$1(svgCode, opt = {}) {
221
+ const resource = normalizeResource$1(opt.resource || "");
222
+ if (opt["glyph-name"] || opt.unicode) return glyphToJSON(svgCode, {
223
+ glyphName: opt["glyph-name"],
224
+ unicode: opt.unicode
225
+ }, resource);
226
+ return svgToJSON(svgCode, resource);
227
+ }
228
+ (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href);
229
+ function toGlyphs(svgCode) {
230
+ const svg = get(svgCode);
231
+ const glyphs = [];
232
+ svg.walkAllGlyph((el) => glyphs.push(el));
233
+ return glyphs;
234
+ }
235
+ function transform(glyphUnicode, svgCode, svgfile) {
236
+ return sourceToIconJsObject$1(svgCode, {
237
+ unicode: glyphUnicode,
238
+ resource: svgfile
239
+ });
240
+ }
241
+ function charToHexCodeStr(char) {
242
+ if (/[!#-&(-[\]-_a-~]/u.test(char)) return char;
243
+ return `\\u${`0000${char.charCodeAt(0).toString(16)}`.slice(-4)}`;
244
+ }
245
+ function toCodeString(code) {
246
+ let result = "";
247
+ for (let i = 0; i < code.length; i++) result += charToHexCodeStr(code[i]);
248
+ return result;
249
+ }
250
+ function buildObjectCode(svgCode, resource, { name = "unicode" } = {}) {
251
+ let script = "{\n";
252
+ toGlyphs(svgCode).forEach((glyph) => {
253
+ const unicode = glyph.getAttribute("unicode") || "";
254
+ const targetName = glyph.getAttribute(name) || "";
255
+ script += `
256
+ '${toCodeString(targetName)}': ${transform(unicode, svgCode, resource).replace(/\r?\n|\r/gu, `
257
+ `)},`;
258
+ });
259
+ script += "\n}";
260
+ return script;
261
+ }
262
+ function normalizeResource(resource) {
263
+ let index = resource.indexOf("\\node_modules\\");
264
+ if (index === -1) index = resource.indexOf("/node_modules/");
265
+ if (index >= 0) return resource.slice(index + 14);
266
+ return resource;
267
+ }
268
+ function sourceToIconsJsObject(svgCode, opt = {}) {
269
+ return buildObjectCode(svgCode, normalizeResource(opt.resource || ""), opt);
270
+ }
271
+ //#endregion
272
+ //#region src/core/transform.ts
273
+ const DEFAULT_QUERY_NAMES = ["cheetah-grid-icon", "cg-icon"];
274
+ const SVG_EXT_RE = /\.svg$/iu;
275
+ function parseId(id) {
276
+ const queryIndex = id.indexOf("?");
277
+ if (queryIndex < 0) return {
278
+ filename: id,
279
+ query: {}
280
+ };
281
+ return {
282
+ filename: id.slice(0, queryIndex),
283
+ query: parseQuery(id.slice(queryIndex + 1))
284
+ };
285
+ }
286
+ function parseQuery(queryText) {
287
+ const query = {};
288
+ if (!queryText) return query;
289
+ queryText.split("&").forEach((part) => {
290
+ if (!part) return;
291
+ const equalIndex = part.indexOf("=");
292
+ const rawKey = equalIndex < 0 ? part : part.slice(0, equalIndex);
293
+ const rawValue = equalIndex < 0 ? true : part.slice(equalIndex + 1);
294
+ query[decode(rawKey)] = rawValue === true ? true : decode(rawValue);
295
+ });
296
+ return query;
297
+ }
298
+ function decode(value) {
299
+ try {
300
+ return decodeURIComponent(value.replace(/\+/gu, " "));
301
+ } catch (_err) {
302
+ return value;
303
+ }
304
+ }
305
+ function normalizeQueryNames(query) {
306
+ if (query === false) return [];
307
+ if (query == null) return DEFAULT_QUERY_NAMES;
308
+ return Array.isArray(query) ? query : [query];
309
+ }
310
+ function hasOwn(object, key) {
311
+ return Object.prototype.hasOwnProperty.call(object, key);
312
+ }
313
+ function matchesPattern(pattern, value) {
314
+ if (pattern == null) return false;
315
+ if (Array.isArray(pattern)) return pattern.some((item) => matchesPattern(item, value));
316
+ if (pattern instanceof RegExp) {
317
+ pattern.lastIndex = 0;
318
+ return pattern.test(value);
319
+ }
320
+ if (typeof pattern === "function") return Boolean(pattern(value));
321
+ return value.indexOf(String(pattern)) >= 0;
322
+ }
323
+ function matchesFilter(pattern, id, filename) {
324
+ return matchesPattern(pattern, id) || matchesPattern(pattern, filename);
325
+ }
326
+ function hasPluginQuery(query, options = {}) {
327
+ return normalizeQueryNames(options.query).some((queryName) => hasOwn(query, queryName));
328
+ }
329
+ function shouldTransform(id, options = {}) {
330
+ const { filename, query } = parseId(id);
331
+ if (!SVG_EXT_RE.test(filename)) return false;
332
+ if (matchesFilter(options.exclude, id, filename)) return false;
333
+ if (hasPluginQuery(query, options)) return true;
334
+ if (options.include != null) return matchesFilter(options.include, id, filename);
335
+ return options.query === false;
336
+ }
337
+ function buildParams(id, options = {}) {
338
+ const { filename, query } = parseId(id);
339
+ const queryNames = normalizeQueryNames(options.query);
340
+ const params = { resource: filename };
341
+ for (const key in query) if (queryNames.indexOf(key) < 0) params[key] = query[key];
342
+ return params;
343
+ }
344
+ function sourceToIconJsObject(source, id, options = {}) {
345
+ const params = buildParams(id, options);
346
+ if (source.indexOf("<font-face") >= 0 && !params["glyph-name"] && !params.unicode) return sourceToIconsJsObject(source, params);
347
+ return sourceToIconJsObject$1(source, params);
348
+ }
349
+ function transformSvg(source, id, options = {}) {
350
+ return {
351
+ code: `export default ${sourceToIconJsObject(source, id, options)};\n`,
352
+ map: { mappings: "" }
353
+ };
354
+ }
355
+ //#endregion
356
+ //#region src/index.ts
357
+ const unplugin$1 = (0, unplugin.createUnplugin)((options = {}) => ({
358
+ name: "unplugin-cheetah-grid-icon-svg",
359
+ enforce: "pre",
360
+ transformInclude(id) {
361
+ return shouldTransform(id, options);
362
+ },
363
+ transform(source, id) {
364
+ if (!shouldTransform(id, options)) return null;
365
+ return transformSvg(source, id, options);
366
+ }
367
+ }));
368
+ //#endregion
369
+ Object.defineProperty(exports, "unplugin", {
370
+ enumerable: true,
371
+ get: function() {
372
+ return unplugin$1;
373
+ }
374
+ });
package/dist/src.mjs ADDED
@@ -0,0 +1,369 @@
1
+ import { createRequire } from "node:module";
2
+ import { createUnplugin } from "unplugin";
3
+ import { DOMParser } from "@xmldom/xmldom";
4
+ //#region src/core/svg-data.ts
5
+ const ELEMENT_NODE = 1;
6
+ const parser = new (typeof window !== "undefined" && window.DOMParser ? window.DOMParser : DOMParser)();
7
+ function isElementNode(node) {
8
+ return node.nodeType === ELEMENT_NODE && typeof node.tagName === "string";
9
+ }
10
+ function findElement(el, test) {
11
+ const { childNodes } = el;
12
+ for (let i = 0; i < childNodes.length; i++) {
13
+ const child = childNodes[i];
14
+ if (!isElementNode(child)) continue;
15
+ if (test(child)) return child;
16
+ const result = findElement(child, test);
17
+ if (result) return result;
18
+ }
19
+ return null;
20
+ }
21
+ var Svg = class {
22
+ constructor(svgCode) {
23
+ this.glyphs = {};
24
+ this.glyphUnicodes = {};
25
+ const document = parser.parseFromString(svgCode, "image/svg+xml");
26
+ this.svg = document.documentElement;
27
+ }
28
+ findElement(test) {
29
+ return findElement(this.svg, test);
30
+ }
31
+ get fontFaceElement() {
32
+ if (this.cachedFontFaceElement === void 0) this.cachedFontFaceElement = this.findElement((child) => child.tagName.toLowerCase() === "font-face");
33
+ return this.cachedFontFaceElement;
34
+ }
35
+ get fontElement() {
36
+ if (this.cachedFontElement === void 0) this.cachedFontElement = this.findElement((child) => child.tagName.toLowerCase() === "font");
37
+ return this.cachedFontElement;
38
+ }
39
+ findGlyph(glyphName) {
40
+ if (!(glyphName in this.glyphs)) this.glyphs[glyphName] = this.findElement((child) => child.getAttribute("glyph-name") === glyphName);
41
+ return this.glyphs[glyphName] || null;
42
+ }
43
+ findGlyphByUnicode(unicode) {
44
+ if (!(unicode in this.glyphUnicodes)) this.glyphUnicodes[unicode] = this.findElement((child) => child.getAttribute("unicode") === unicode);
45
+ return this.glyphUnicodes[unicode] || null;
46
+ }
47
+ walkAllGlyph(callback) {
48
+ const walkGlyph = (el) => {
49
+ const { childNodes } = el;
50
+ for (let i = 0; i < childNodes.length; i++) {
51
+ const child = childNodes[i];
52
+ if (!isElementNode(child)) continue;
53
+ const unicode = child.getAttribute("unicode");
54
+ if (unicode && child.getAttribute("d")) {
55
+ if (!this.glyphUnicodes[unicode]) this.glyphUnicodes[unicode] = child;
56
+ const glyphName = child.getAttribute("glyph-name");
57
+ if (glyphName && !this.glyphs[glyphName]) this.glyphs[glyphName] = child;
58
+ callback(child);
59
+ } else walkGlyph(child);
60
+ }
61
+ };
62
+ walkGlyph(this.svg);
63
+ }
64
+ };
65
+ const cache = {};
66
+ function get(svgCode) {
67
+ const cacheKey = `font:${svgCode}`;
68
+ cache[cacheKey] = cache[cacheKey] || new Svg(svgCode);
69
+ return cache[cacheKey];
70
+ }
71
+ createRequire(import.meta.url);
72
+ function attr(el, name) {
73
+ return el.getAttribute(name) || "";
74
+ }
75
+ function polygonToPath(polygon) {
76
+ return `M${attr(polygon, "points")}z`;
77
+ }
78
+ function polylineToPath(polyline) {
79
+ return `M${attr(polyline, "points")}`;
80
+ }
81
+ function circleToPath(circle) {
82
+ const cx = Number(attr(circle, "cx"));
83
+ const cy = Number(attr(circle, "cy"));
84
+ const r = Number(attr(circle, "r"));
85
+ const segments = 8;
86
+ const angle = 2 * Math.PI / segments;
87
+ const anchorX = (theta) => r * Math.cos(theta);
88
+ const anchorY = (theta) => r * Math.sin(theta);
89
+ const controlX = (theta) => anchorX(theta) + r * Math.tan(angle / 2) * Math.cos(theta - Math.PI / 2);
90
+ const controlY = (theta) => anchorY(theta) + r * Math.tan(angle / 2) * Math.sin(theta - Math.PI / 2);
91
+ let paths = `M${cx + r} ${cy}`;
92
+ for (let index = 1; index <= segments; index++) {
93
+ const theta = index * angle;
94
+ paths += `Q${controlX(theta) + cx} ${controlY(theta) + cy} ${anchorX(theta) + cx} ${anchorY(theta) + cy}`;
95
+ }
96
+ return paths;
97
+ }
98
+ function rectToPath(rect) {
99
+ const x = Number(attr(rect, "x"));
100
+ const y = Number(attr(rect, "y"));
101
+ const width = Number(attr(rect, "width"));
102
+ return `M${x},${y} h${width} v${Number(attr(rect, "height"))} h${-width}z`;
103
+ }
104
+ function getD(path) {
105
+ if (path.getAttribute("fill") === "none") return "";
106
+ return attr(path, "d").replace(/[\n\r]/gu, "");
107
+ }
108
+ function elementToPaths(el, resource) {
109
+ switch (el.tagName.toLowerCase()) {
110
+ case "path":
111
+ case "glyph": return getD(el);
112
+ case "circle": return circleToPath(el);
113
+ case "polygon": return polygonToPath(el);
114
+ case "polyline": return polylineToPath(el);
115
+ case "rect": return rectToPath(el);
116
+ case "g": {
117
+ let path = "";
118
+ const { childNodes } = el;
119
+ for (let i = 0; i < childNodes.length; i++) {
120
+ const child = childNodes[i];
121
+ if (!isElementNode(child)) continue;
122
+ if (!child.getAttribute("fill")) child.setAttribute("fill", el.getAttribute("fill"));
123
+ path += elementToPaths(child, resource);
124
+ }
125
+ return path;
126
+ }
127
+ default: console.warn(`unsupported:${el.tagName}`, `@ ${resource}\n${el.innerHTML}`);
128
+ }
129
+ return "";
130
+ }
131
+ function buildScript({ offsetX = 0, offsetY = 0, width, height, d, isGlyph, html, resource }) {
132
+ let flags = "";
133
+ if (isGlyph) flags += `ud: 1,
134
+ `;
135
+ if (offsetX !== 0) flags += `x: ${offsetX},
136
+ `;
137
+ if (offsetY !== 0) flags += `y: ${offsetY},
138
+ `;
139
+ return `{
140
+ /*
141
+ original svg
142
+ ${html}
143
+ @ ${resource}
144
+ */
145
+ d: '${d}',
146
+ width: ${width},
147
+ height: ${height},
148
+ ${flags}
149
+ }`;
150
+ }
151
+ function glyphToJSON(svgString, { glyphName, unicode }, resource) {
152
+ const svg = get(svgString);
153
+ const findGlyph = () => {
154
+ if (glyphName && glyphName !== true) return svg.findGlyph(glyphName);
155
+ return unicode && unicode !== true ? svg.findGlyphByUnicode(unicode) : null;
156
+ };
157
+ const emptyElement = { getAttribute: () => "" };
158
+ const fontFace = svg.fontFaceElement || emptyElement;
159
+ const font = svg.fontElement || emptyElement;
160
+ const glyph = findGlyph();
161
+ if (!glyph) throw new Error(`Glyph not found: ${glyphName && glyphName !== true ? glyphName : unicode && unicode !== true ? unicode : ""}`);
162
+ const fontHorizAdvX = Number(font.getAttribute("horiz-adv-x")) || 0;
163
+ const fontVertAdvX = Number(font.getAttribute("vert-adv-x")) || 0;
164
+ const horizAdvX = Number(glyph.getAttribute("horiz-adv-x")) || fontHorizAdvX || 0;
165
+ const vertAdvX = Number(glyph.getAttribute("vert-adv-x")) || fontVertAdvX || 0;
166
+ const unitsPerEm = Number(fontFace.getAttribute("units-per-em")) || 1e3;
167
+ const descent = Number(fontFace.getAttribute("descent")) || vertAdvX;
168
+ let size = unitsPerEm;
169
+ const contentSize = {
170
+ width: horizAdvX || unitsPerEm,
171
+ height: vertAdvX || unitsPerEm
172
+ };
173
+ if (horizAdvX > size) size = horizAdvX;
174
+ if (vertAdvX > size) size = vertAdvX;
175
+ let offsetX = 0;
176
+ let offsetY = -descent;
177
+ offsetX += Math.round((size - contentSize.width) / 2);
178
+ offsetY += Math.round((size - contentSize.height) / 2);
179
+ return buildScript({
180
+ offsetX,
181
+ offsetY,
182
+ width: size,
183
+ height: size,
184
+ d: elementToPaths(glyph, resource),
185
+ isGlyph: true,
186
+ html: glyph.outerHTML,
187
+ resource
188
+ });
189
+ }
190
+ function svgToJSON(svgString, resource) {
191
+ const { svg } = get(svgString);
192
+ const viewBox = attr(svg, "viewBox").split(" ");
193
+ const width = Number(attr(svg, "width") || viewBox[2]) || 0;
194
+ const height = Number(attr(svg, "height") || viewBox[3]) || 0;
195
+ const offsetX = 0 - Number(viewBox[0]) || 0;
196
+ const offsetY = 0 - Number(viewBox[1]) || 0;
197
+ let d = "";
198
+ const { childNodes } = svg;
199
+ for (let i = 0; i < childNodes.length; i++) {
200
+ const el = childNodes[i];
201
+ if (!isElementNode(el)) continue;
202
+ d += elementToPaths(el, resource);
203
+ }
204
+ return buildScript({
205
+ offsetX,
206
+ offsetY,
207
+ width,
208
+ height,
209
+ d,
210
+ html: svgString,
211
+ resource
212
+ });
213
+ }
214
+ function normalizeResource$1(resource) {
215
+ let index = resource.indexOf("\\node_modules\\");
216
+ if (index === -1) index = resource.indexOf("/node_modules/");
217
+ if (index >= 0) return resource.slice(index + 14);
218
+ return resource;
219
+ }
220
+ function sourceToIconJsObject$1(svgCode, opt = {}) {
221
+ const resource = normalizeResource$1(opt.resource || "");
222
+ if (opt["glyph-name"] || opt.unicode) return glyphToJSON(svgCode, {
223
+ glyphName: opt["glyph-name"],
224
+ unicode: opt.unicode
225
+ }, resource);
226
+ return svgToJSON(svgCode, resource);
227
+ }
228
+ createRequire(import.meta.url);
229
+ function toGlyphs(svgCode) {
230
+ const svg = get(svgCode);
231
+ const glyphs = [];
232
+ svg.walkAllGlyph((el) => glyphs.push(el));
233
+ return glyphs;
234
+ }
235
+ function transform(glyphUnicode, svgCode, svgfile) {
236
+ return sourceToIconJsObject$1(svgCode, {
237
+ unicode: glyphUnicode,
238
+ resource: svgfile
239
+ });
240
+ }
241
+ function charToHexCodeStr(char) {
242
+ if (/[!#-&(-[\]-_a-~]/u.test(char)) return char;
243
+ return `\\u${`0000${char.charCodeAt(0).toString(16)}`.slice(-4)}`;
244
+ }
245
+ function toCodeString(code) {
246
+ let result = "";
247
+ for (let i = 0; i < code.length; i++) result += charToHexCodeStr(code[i]);
248
+ return result;
249
+ }
250
+ function buildObjectCode(svgCode, resource, { name = "unicode" } = {}) {
251
+ let script = "{\n";
252
+ toGlyphs(svgCode).forEach((glyph) => {
253
+ const unicode = glyph.getAttribute("unicode") || "";
254
+ const targetName = glyph.getAttribute(name) || "";
255
+ script += `
256
+ '${toCodeString(targetName)}': ${transform(unicode, svgCode, resource).replace(/\r?\n|\r/gu, `
257
+ `)},`;
258
+ });
259
+ script += "\n}";
260
+ return script;
261
+ }
262
+ function normalizeResource(resource) {
263
+ let index = resource.indexOf("\\node_modules\\");
264
+ if (index === -1) index = resource.indexOf("/node_modules/");
265
+ if (index >= 0) return resource.slice(index + 14);
266
+ return resource;
267
+ }
268
+ function sourceToIconsJsObject(svgCode, opt = {}) {
269
+ return buildObjectCode(svgCode, normalizeResource(opt.resource || ""), opt);
270
+ }
271
+ //#endregion
272
+ //#region src/core/transform.ts
273
+ const DEFAULT_QUERY_NAMES = ["cheetah-grid-icon", "cg-icon"];
274
+ const SVG_EXT_RE = /\.svg$/iu;
275
+ function parseId(id) {
276
+ const queryIndex = id.indexOf("?");
277
+ if (queryIndex < 0) return {
278
+ filename: id,
279
+ query: {}
280
+ };
281
+ return {
282
+ filename: id.slice(0, queryIndex),
283
+ query: parseQuery(id.slice(queryIndex + 1))
284
+ };
285
+ }
286
+ function parseQuery(queryText) {
287
+ const query = {};
288
+ if (!queryText) return query;
289
+ queryText.split("&").forEach((part) => {
290
+ if (!part) return;
291
+ const equalIndex = part.indexOf("=");
292
+ const rawKey = equalIndex < 0 ? part : part.slice(0, equalIndex);
293
+ const rawValue = equalIndex < 0 ? true : part.slice(equalIndex + 1);
294
+ query[decode(rawKey)] = rawValue === true ? true : decode(rawValue);
295
+ });
296
+ return query;
297
+ }
298
+ function decode(value) {
299
+ try {
300
+ return decodeURIComponent(value.replace(/\+/gu, " "));
301
+ } catch (_err) {
302
+ return value;
303
+ }
304
+ }
305
+ function normalizeQueryNames(query) {
306
+ if (query === false) return [];
307
+ if (query == null) return DEFAULT_QUERY_NAMES;
308
+ return Array.isArray(query) ? query : [query];
309
+ }
310
+ function hasOwn(object, key) {
311
+ return Object.prototype.hasOwnProperty.call(object, key);
312
+ }
313
+ function matchesPattern(pattern, value) {
314
+ if (pattern == null) return false;
315
+ if (Array.isArray(pattern)) return pattern.some((item) => matchesPattern(item, value));
316
+ if (pattern instanceof RegExp) {
317
+ pattern.lastIndex = 0;
318
+ return pattern.test(value);
319
+ }
320
+ if (typeof pattern === "function") return Boolean(pattern(value));
321
+ return value.indexOf(String(pattern)) >= 0;
322
+ }
323
+ function matchesFilter(pattern, id, filename) {
324
+ return matchesPattern(pattern, id) || matchesPattern(pattern, filename);
325
+ }
326
+ function hasPluginQuery(query, options = {}) {
327
+ return normalizeQueryNames(options.query).some((queryName) => hasOwn(query, queryName));
328
+ }
329
+ function shouldTransform(id, options = {}) {
330
+ const { filename, query } = parseId(id);
331
+ if (!SVG_EXT_RE.test(filename)) return false;
332
+ if (matchesFilter(options.exclude, id, filename)) return false;
333
+ if (hasPluginQuery(query, options)) return true;
334
+ if (options.include != null) return matchesFilter(options.include, id, filename);
335
+ return options.query === false;
336
+ }
337
+ function buildParams(id, options = {}) {
338
+ const { filename, query } = parseId(id);
339
+ const queryNames = normalizeQueryNames(options.query);
340
+ const params = { resource: filename };
341
+ for (const key in query) if (queryNames.indexOf(key) < 0) params[key] = query[key];
342
+ return params;
343
+ }
344
+ function sourceToIconJsObject(source, id, options = {}) {
345
+ const params = buildParams(id, options);
346
+ if (source.indexOf("<font-face") >= 0 && !params["glyph-name"] && !params.unicode) return sourceToIconsJsObject(source, params);
347
+ return sourceToIconJsObject$1(source, params);
348
+ }
349
+ function transformSvg(source, id, options = {}) {
350
+ return {
351
+ code: `export default ${sourceToIconJsObject(source, id, options)};\n`,
352
+ map: { mappings: "" }
353
+ };
354
+ }
355
+ //#endregion
356
+ //#region src/index.ts
357
+ const unplugin = createUnplugin((options = {}) => ({
358
+ name: "unplugin-cheetah-grid-icon-svg",
359
+ enforce: "pre",
360
+ transformInclude(id) {
361
+ return shouldTransform(id, options);
362
+ },
363
+ transform(source, id) {
364
+ if (!shouldTransform(id, options)) return null;
365
+ return transformSvg(source, id, options);
366
+ }
367
+ }));
368
+ //#endregion
369
+ export { unplugin as t };
package/dist/vite.cjs ADDED
@@ -0,0 +1,4 @@
1
+ //#region src/vite.ts
2
+ var vite_default = require("./src.cjs").unplugin.vite;
3
+ //#endregion
4
+ module.exports = vite_default;
@@ -0,0 +1,7 @@
1
+ import { r as Options } from "./index.mjs";
2
+ import * as vite0 from "vite";
3
+
4
+ //#region src/vite.d.ts
5
+ declare const _default: (options?: Options | undefined) => vite0.Plugin<any> | vite0.Plugin<any>[];
6
+ //#endregion
7
+ export { _default as default };
package/dist/vite.mjs ADDED
@@ -0,0 +1,5 @@
1
+ import { t as unplugin } from "./src.mjs";
2
+ //#region src/vite.ts
3
+ var vite_default = unplugin.vite;
4
+ //#endregion
5
+ export { vite_default as default };
@@ -0,0 +1,4 @@
1
+ //#region src/webpack.ts
2
+ var webpack_default = require("./src.cjs").unplugin.webpack;
3
+ //#endregion
4
+ module.exports = webpack_default;
@@ -0,0 +1,6 @@
1
+ import { r as Options } from "./index.mjs";
2
+
3
+ //#region src/webpack.d.ts
4
+ declare const _default: (options?: Options | undefined) => WebpackPluginInstance;
5
+ //#endregion
6
+ export { _default as default };
@@ -0,0 +1,5 @@
1
+ import { t as unplugin } from "./src.mjs";
2
+ //#region src/webpack.ts
3
+ var webpack_default = unplugin.webpack;
4
+ //#endregion
5
+ export { webpack_default as default };
package/package.json ADDED
@@ -0,0 +1,137 @@
1
+ {
2
+ "name": "unplugin-cheetah-grid-icon-svg",
3
+ "version": "0.0.0",
4
+ "description": "Unplugin that loads the icon module for Cheetah Grid from SVG.",
5
+ "main": "dist/index.cjs",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.mts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.mts",
11
+ "require": "./dist/index.cjs",
12
+ "import": "./dist/index.mjs"
13
+ },
14
+ "./vite": {
15
+ "types": "./dist/vite.d.mts",
16
+ "require": "./dist/vite.cjs",
17
+ "import": "./dist/vite.mjs"
18
+ },
19
+ "./rollup": {
20
+ "types": "./dist/rollup.d.mts",
21
+ "require": "./dist/rollup.cjs",
22
+ "import": "./dist/rollup.mjs"
23
+ },
24
+ "./rolldown": {
25
+ "types": "./dist/rolldown.d.mts",
26
+ "require": "./dist/rolldown.cjs",
27
+ "import": "./dist/rolldown.mjs"
28
+ },
29
+ "./webpack": {
30
+ "types": "./dist/webpack.d.mts",
31
+ "require": "./dist/webpack.cjs",
32
+ "import": "./dist/webpack.mjs"
33
+ },
34
+ "./rspack": {
35
+ "types": "./dist/rspack.d.mts",
36
+ "require": "./dist/rspack.cjs",
37
+ "import": "./dist/rspack.mjs"
38
+ },
39
+ "./esbuild": {
40
+ "types": "./dist/esbuild.d.mts",
41
+ "require": "./dist/esbuild.cjs",
42
+ "import": "./dist/esbuild.mjs"
43
+ }
44
+ },
45
+ "files": [
46
+ "dist"
47
+ ],
48
+ "scripts": {
49
+ "pretest": "npm run lint",
50
+ "test:base": "vitest run",
51
+ "test": "npm run build && vitest run --coverage",
52
+ "test:nyc": "npm run test",
53
+ "test:d": "vitest --inspect-brk",
54
+ "watch": "vitest",
55
+ "build": "npm run build:tsdown",
56
+ "build:tsdown": "tsdown",
57
+ "prepack": "npm run build",
58
+ "lint": "npm run eslint && npm run tsc",
59
+ "eslint": "eslint . --ext .js,.ts",
60
+ "eslint:fix": "eslint . --fix --ext .js,.ts",
61
+ "tsc": "tsc --project ./tsconfig.json"
62
+ },
63
+ "repository": {
64
+ "type": "git",
65
+ "url": "https://github.com/future-architect/cheetah-grid.git"
66
+ },
67
+ "keywords": [
68
+ "svg",
69
+ "vite",
70
+ "rollup",
71
+ "rolldown",
72
+ "webpack",
73
+ "unplugin",
74
+ "icon",
75
+ "cheetah-grid"
76
+ ],
77
+ "author": {
78
+ "name": "yosuke ota",
79
+ "email": "otameshiyo23@gmail.com",
80
+ "url": "https://www.npmjs.com/~ota-meshi"
81
+ },
82
+ "license": "MIT",
83
+ "bugs": {
84
+ "url": "https://github.com/future-architect/cheetah-grid/issues"
85
+ },
86
+ "homepage": "https://github.com/future-architect/cheetah-grid/tree/master/packages/unplugin-cheetah-grid-icon-svg",
87
+ "dependencies": {
88
+ "@xmldom/xmldom": "^0.9.10",
89
+ "unplugin": "^2.3.10"
90
+ },
91
+ "devDependencies": {
92
+ "@types/node": "^24.12.4",
93
+ "@typescript-eslint/eslint-plugin": "^4.0.0",
94
+ "@typescript-eslint/parser": "^4.0.0",
95
+ "@vitest/coverage-v8": "^4.1.6",
96
+ "eslint": "^7.11.0",
97
+ "eslint-config-prettier": "^6.11.0",
98
+ "eslint-plugin-node": "^11.1.0",
99
+ "eslint-plugin-prettier": "^3.1.4",
100
+ "font-awesome": "^4.7.0",
101
+ "prettier": "^2.5.1",
102
+ "tsdown": "^0.14.1",
103
+ "typescript": "^5.9.2",
104
+ "vitest": "^4.1.6"
105
+ },
106
+ "engines": {
107
+ "node": "^22.12.0 || ^24.11.0"
108
+ },
109
+ "peerDependencies": {
110
+ "@rspack/core": ">=0.5.0",
111
+ "esbuild": ">=0.14.0",
112
+ "rolldown": ">=1.0.0-beta.0",
113
+ "rollup": ">=2.0.0",
114
+ "vite": ">=2.0.0",
115
+ "webpack": ">=4.0.0"
116
+ },
117
+ "peerDependenciesMeta": {
118
+ "vite": {
119
+ "optional": true
120
+ },
121
+ "webpack": {
122
+ "optional": true
123
+ },
124
+ "rollup": {
125
+ "optional": true
126
+ },
127
+ "rolldown": {
128
+ "optional": true
129
+ },
130
+ "esbuild": {
131
+ "optional": true
132
+ },
133
+ "@rspack/core": {
134
+ "optional": true
135
+ }
136
+ }
137
+ }