react-icons-sprite 1.1.1 → 1.2.0-rc.2
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.
|
@@ -237,6 +237,123 @@ const scanJsxIconEdits = (code, symbols, componentName, usedSymbols, register, h
|
|
|
237
237
|
count
|
|
238
238
|
};
|
|
239
239
|
};
|
|
240
|
+
const scanJsxReferencePropEdits = (code, symbols, componentName, usedSymbols, register, ignoredComponentLocals) => {
|
|
241
|
+
if (symbols.size === 0) return {
|
|
242
|
+
edits: [],
|
|
243
|
+
count: 0
|
|
244
|
+
};
|
|
245
|
+
const edits = [];
|
|
246
|
+
let count = 0;
|
|
247
|
+
for (let index = code.indexOf("<"); index !== -1; index = code.indexOf("<", index + 1)) {
|
|
248
|
+
let cursor = index + 1;
|
|
249
|
+
while (isWhitespace(code[cursor])) cursor += 1;
|
|
250
|
+
if (code[cursor] === "/") continue;
|
|
251
|
+
if (!isIdentifierStart(code[cursor])) continue;
|
|
252
|
+
const componentStart = cursor;
|
|
253
|
+
cursor += 1;
|
|
254
|
+
while (isIdentifierPart(code[cursor])) cursor += 1;
|
|
255
|
+
const componentLocal = code.slice(componentStart, cursor);
|
|
256
|
+
if (symbols.items[componentLocal] || ignoredComponentLocals.has(componentLocal)) continue;
|
|
257
|
+
const tagEnd = findJsxOpeningTagEnd(code, cursor);
|
|
258
|
+
if (tagEnd === -1) continue;
|
|
259
|
+
let attributeCursor = cursor;
|
|
260
|
+
while (attributeCursor < tagEnd) {
|
|
261
|
+
while (isWhitespace(code[attributeCursor])) attributeCursor += 1;
|
|
262
|
+
if (attributeCursor >= tagEnd || code[attributeCursor] === "/") break;
|
|
263
|
+
if (code[attributeCursor] === "{") {
|
|
264
|
+
const expressionEnd = findJsxExpressionEnd(code, attributeCursor);
|
|
265
|
+
attributeCursor = expressionEnd === -1 ? tagEnd : expressionEnd + 1;
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
if (!isIdentifierStart(code[attributeCursor])) {
|
|
269
|
+
attributeCursor += 1;
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
attributeCursor += 1;
|
|
273
|
+
while (isJsxAttributeNamePart(code[attributeCursor])) attributeCursor += 1;
|
|
274
|
+
while (isWhitespace(code[attributeCursor])) attributeCursor += 1;
|
|
275
|
+
if (code[attributeCursor] !== "=") continue;
|
|
276
|
+
attributeCursor += 1;
|
|
277
|
+
while (isWhitespace(code[attributeCursor])) attributeCursor += 1;
|
|
278
|
+
const valueStart = attributeCursor;
|
|
279
|
+
if (code[valueStart] === "\"" || code[valueStart] === "'") {
|
|
280
|
+
attributeCursor = skipQuotedString(code, valueStart);
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
if (code[valueStart] !== "{") continue;
|
|
284
|
+
const expressionEnd = findJsxExpressionEnd(code, valueStart);
|
|
285
|
+
if (expressionEnd === -1 || expressionEnd > tagEnd) {
|
|
286
|
+
attributeCursor = tagEnd;
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
attributeCursor = expressionEnd + 1;
|
|
290
|
+
const expression = code.slice(valueStart + 1, expressionEnd);
|
|
291
|
+
const iconMatch = /^(\s*)([A-Za-z_$][\w$]*)(\s*)$/.exec(expression);
|
|
292
|
+
if (!iconMatch) continue;
|
|
293
|
+
const iconLocal = iconMatch[2];
|
|
294
|
+
const symbol = symbols.items[iconLocal];
|
|
295
|
+
if (!symbol || isFontAwesomeIconPack(symbol.pack) || isHugeiconsIconPack(symbol.pack)) continue;
|
|
296
|
+
const iconLocalStart = valueStart + 1 + iconMatch[1].length;
|
|
297
|
+
edits.push({
|
|
298
|
+
type: "replace",
|
|
299
|
+
from: iconLocalStart,
|
|
300
|
+
to: iconLocalStart + iconLocal.length,
|
|
301
|
+
value: `(props) => <${componentName} {...props} iconId="${symbol.iconId}" />`
|
|
302
|
+
});
|
|
303
|
+
count += 1;
|
|
304
|
+
usedSymbols.add(iconLocal);
|
|
305
|
+
register(symbol.pack, symbol.exportName);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
return {
|
|
309
|
+
edits,
|
|
310
|
+
count
|
|
311
|
+
};
|
|
312
|
+
};
|
|
313
|
+
const isJsxAttributeNamePart = (char) => {
|
|
314
|
+
return isIdentifierPart(char) || char === "-" || char === "." || char === ":";
|
|
315
|
+
};
|
|
316
|
+
const skipQuotedString = (code, start) => {
|
|
317
|
+
const quote = code[start];
|
|
318
|
+
let cursor = start + 1;
|
|
319
|
+
while (cursor < code.length) {
|
|
320
|
+
if (code[cursor] === "\\") {
|
|
321
|
+
cursor += 2;
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
if (code[cursor] === quote) return cursor + 1;
|
|
325
|
+
cursor += 1;
|
|
326
|
+
}
|
|
327
|
+
return code.length;
|
|
328
|
+
};
|
|
329
|
+
const findJsxExpressionEnd = (code, start) => {
|
|
330
|
+
let quote = null;
|
|
331
|
+
let braceDepth = 0;
|
|
332
|
+
for (let index = start; index < code.length; index += 1) {
|
|
333
|
+
const char = code[index];
|
|
334
|
+
if (quote) {
|
|
335
|
+
if (char === "\\") {
|
|
336
|
+
index += 1;
|
|
337
|
+
continue;
|
|
338
|
+
}
|
|
339
|
+
if (char === quote) quote = null;
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
if (char === "\"" || char === "'" || char === "`") {
|
|
343
|
+
quote = char;
|
|
344
|
+
continue;
|
|
345
|
+
}
|
|
346
|
+
if (char === "{") {
|
|
347
|
+
braceDepth += 1;
|
|
348
|
+
continue;
|
|
349
|
+
}
|
|
350
|
+
if (char === "}") {
|
|
351
|
+
braceDepth -= 1;
|
|
352
|
+
if (braceDepth === 0) return index;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
return -1;
|
|
356
|
+
};
|
|
240
357
|
const hasIconIdAttribute = (code, start, end) => {
|
|
241
358
|
for (let index = start; index < end; index += 1) {
|
|
242
359
|
if (code.charCodeAt(index) !== 105 || code.charCodeAt(index + 1) !== 99 || code.charCodeAt(index + 2) !== 111 || code.charCodeAt(index + 3) !== 110 || code.charCodeAt(index + 4) !== 73 || code.charCodeAt(index + 5) !== 100) continue;
|
|
@@ -466,6 +583,82 @@ const consumeTrailingWhitespace = (code, start) => {
|
|
|
466
583
|
while (to < code.length && isWhitespaceCode(code.charCodeAt(to))) to += 1;
|
|
467
584
|
return to;
|
|
468
585
|
};
|
|
586
|
+
const editRange = (edit) => {
|
|
587
|
+
if (edit.type === "insert") return null;
|
|
588
|
+
return [edit.from, edit.to];
|
|
589
|
+
};
|
|
590
|
+
const rangeContains = ([start, end], index) => {
|
|
591
|
+
return index >= start && index < end;
|
|
592
|
+
};
|
|
593
|
+
const collectUsedLocalsOutsideRanges = (code, usedLocals, ignoredRanges) => {
|
|
594
|
+
const ranges = [...ignoredRanges].sort((left, right) => left[0] - right[0]);
|
|
595
|
+
const found = /* @__PURE__ */ new Set();
|
|
596
|
+
let rangeIndex = 0;
|
|
597
|
+
let quote = null;
|
|
598
|
+
let lineComment = false;
|
|
599
|
+
let blockComment = false;
|
|
600
|
+
for (let index = 0; index < code.length; index += 1) {
|
|
601
|
+
while (rangeIndex < ranges.length && ranges[rangeIndex][1] <= index) rangeIndex += 1;
|
|
602
|
+
const ignoredRange = ranges[rangeIndex];
|
|
603
|
+
if (ignoredRange && rangeContains(ignoredRange, index)) {
|
|
604
|
+
index = ignoredRange[1] - 1;
|
|
605
|
+
continue;
|
|
606
|
+
}
|
|
607
|
+
const char = code[index];
|
|
608
|
+
const next = code[index + 1];
|
|
609
|
+
if (lineComment) {
|
|
610
|
+
if (char === "\n" || char === "\r") lineComment = false;
|
|
611
|
+
continue;
|
|
612
|
+
}
|
|
613
|
+
if (blockComment) {
|
|
614
|
+
if (char === "*" && next === "/") {
|
|
615
|
+
blockComment = false;
|
|
616
|
+
index += 1;
|
|
617
|
+
}
|
|
618
|
+
continue;
|
|
619
|
+
}
|
|
620
|
+
if (quote) {
|
|
621
|
+
if (char === "\\") {
|
|
622
|
+
index += 1;
|
|
623
|
+
continue;
|
|
624
|
+
}
|
|
625
|
+
if (char === quote) quote = null;
|
|
626
|
+
continue;
|
|
627
|
+
}
|
|
628
|
+
if (char === "/" && next === "/") {
|
|
629
|
+
lineComment = true;
|
|
630
|
+
index += 1;
|
|
631
|
+
continue;
|
|
632
|
+
}
|
|
633
|
+
if (char === "/" && next === "*") {
|
|
634
|
+
blockComment = true;
|
|
635
|
+
index += 1;
|
|
636
|
+
continue;
|
|
637
|
+
}
|
|
638
|
+
if (char === "\"" || char === "'") {
|
|
639
|
+
quote = char;
|
|
640
|
+
continue;
|
|
641
|
+
}
|
|
642
|
+
if (!isIdentifierStart(char)) continue;
|
|
643
|
+
const start = index;
|
|
644
|
+
index += 1;
|
|
645
|
+
while (isIdentifierPart(code[index])) index += 1;
|
|
646
|
+
const local = code.slice(start, index);
|
|
647
|
+
if (usedLocals.has(local)) found.add(local);
|
|
648
|
+
index -= 1;
|
|
649
|
+
}
|
|
650
|
+
return found;
|
|
651
|
+
};
|
|
652
|
+
const filterRemovableUsedLocals = (code, imports, usedLocals, usageEdits) => {
|
|
653
|
+
const ignoredRanges = [...imports.map((item) => item.declarationRange), ...usageEdits.flatMap((edit) => {
|
|
654
|
+
const range = editRange(edit);
|
|
655
|
+
return range ? [range] : [];
|
|
656
|
+
})];
|
|
657
|
+
const liveLocals = collectUsedLocalsOutsideRanges(code, usedLocals, ignoredRanges);
|
|
658
|
+
const removable = /* @__PURE__ */ new Set();
|
|
659
|
+
for (const local of usedLocals) if (!liveLocals.has(local)) removable.add(local);
|
|
660
|
+
return removable;
|
|
661
|
+
};
|
|
469
662
|
const transformModule = (code, id, register, sources = DEFAULT_ICON_SOURCES, options = {}) => {
|
|
470
663
|
const { sourceMap = false } = options;
|
|
471
664
|
if (!fastFilter(code)) return {
|
|
@@ -492,17 +685,21 @@ const transformModule = (code, id, register, sources = DEFAULT_ICON_SOURCES, opt
|
|
|
492
685
|
localName: ICON_COMPONENT_NAME
|
|
493
686
|
};
|
|
494
687
|
const used = /* @__PURE__ */ new Set();
|
|
688
|
+
const fontAwesomeComponents = hasPotentialFontAwesomeUsage ? scanFontAwesomeComponents(code) : /* @__PURE__ */ new Set();
|
|
689
|
+
const hugeiconsComponents = hasPotentialHugeiconsUsage ? scanHugeiconsComponents(code) : /* @__PURE__ */ new Set();
|
|
495
690
|
const usedFontAwesomeComponents = /* @__PURE__ */ new Set();
|
|
496
691
|
const usedHugeiconsComponents = /* @__PURE__ */ new Set();
|
|
692
|
+
const ignoredIconPropComponentLocals = /* @__PURE__ */ new Set([...fontAwesomeComponents, ...hugeiconsComponents]);
|
|
497
693
|
const jsxScan = scanJsxIconEdits(code, table, spriteIconImport.localName, used, register, code.includes("iconId"));
|
|
498
|
-
const
|
|
499
|
-
const
|
|
500
|
-
|
|
694
|
+
const referencePropScan = scanJsxReferencePropEdits(code, table, spriteIconImport.localName, used, register, ignoredIconPropComponentLocals);
|
|
695
|
+
const fontAwesomeUsages = hasPotentialFontAwesomeUsage ? scanFontAwesomeUsages(code, table, fontAwesomeComponents) : [];
|
|
696
|
+
const hugeiconsUsages = hasPotentialHugeiconsUsage ? scanHugeiconsUsages(code, table, hugeiconsComponents) : [];
|
|
697
|
+
if (jsxScan.count === 0 && referencePropScan.count === 0 && !fontAwesomeUsages.length && !hugeiconsUsages.length) return {
|
|
501
698
|
code,
|
|
502
699
|
map: null,
|
|
503
700
|
anyReplacements: false
|
|
504
701
|
};
|
|
505
|
-
const edits = jsxScan.edits;
|
|
702
|
+
const edits = [...jsxScan.edits, ...referencePropScan.edits];
|
|
506
703
|
const registeredFontAwesomeIcons = /* @__PURE__ */ new Set();
|
|
507
704
|
for (const usage of fontAwesomeUsages) {
|
|
508
705
|
edits.push({
|
|
@@ -555,10 +752,11 @@ const transformModule = (code, id, register, sources = DEFAULT_ICON_SOURCES, opt
|
|
|
555
752
|
register(usage.pack, usage.exportName);
|
|
556
753
|
}
|
|
557
754
|
}
|
|
558
|
-
const
|
|
755
|
+
const removableUsed = filterRemovableUsedLocals(code, scannedImports, used, edits);
|
|
756
|
+
const cleanupEdits = cleanupScannedImports(code, scannedImports, removableUsed);
|
|
559
757
|
const cleanupFontAwesomeEdits = usedFontAwesomeComponents.size ? cleanupScannedFontAwesomeComponentImports(code, usedFontAwesomeComponents) : [];
|
|
560
758
|
const cleanupHugeiconsEdits = usedHugeiconsComponents.size ? cleanupScannedHugeiconsComponentImports(code, usedHugeiconsComponents) : [];
|
|
561
|
-
const canUsePresortedEdits = cleanupFontAwesomeEdits.length === 0 && cleanupHugeiconsEdits.length === 0;
|
|
759
|
+
const canUsePresortedEdits = referencePropScan.count === 0 && cleanupFontAwesomeEdits.length === 0 && cleanupHugeiconsEdits.length === 0;
|
|
562
760
|
const allEdits = canUsePresortedEdits ? [...cleanupEdits, ...edits] : [
|
|
563
761
|
...edits,
|
|
564
762
|
...cleanupEdits,
|
package/dist/vite/plugin.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { REACT_ICONS_SPRITE_URL_PLACEHOLDER } from "../index.mjs";
|
|
2
2
|
import { a as createCollector, r as DEFAULT_ICON_SOURCES } from "../compute-icon-id-Xx4G3fva.mjs";
|
|
3
3
|
import { t as buildSprite } from "../build-sprite-CxqvU2LE.mjs";
|
|
4
|
-
import { t as transformModule } from "../transform-module-
|
|
4
|
+
import { t as transformModule } from "../transform-module-3mbTFhoj.mjs";
|
|
5
5
|
import { createHash } from "node:crypto";
|
|
6
6
|
//#region src/vite/plugin.ts
|
|
7
7
|
const reactIconsSprite = (options = {}) => {
|
package/dist/webpack/loader.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as transformModule } from "../transform-module-
|
|
1
|
+
import { t as transformModule } from "../transform-module-3mbTFhoj.mjs";
|
|
2
2
|
import { t as collector } from "../collector-CBRz9R_h.mjs";
|
|
3
3
|
//#region src/webpack/loader.ts
|
|
4
4
|
const reactIconsSpriteLoader = async function(source) {
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://www.schemastore.org/package.json",
|
|
3
3
|
"name": "react-icons-sprite",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.2.0-rc.2",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "A lightweight Vite, Rsbuild and Webpack plugin for react-icons that builds a single SVG sprite and rewrites icons to <use>, reducing bundle size and runtime overhead.",
|
|
7
7
|
"author": "Jure Rotar <hello@jurerotar.com>",
|