gofront 1.2.2 → 1.2.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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/minifier.js +152 -34
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gofront",
3
- "version": "1.2.2",
3
+ "version": "1.2.3",
4
4
  "author": "Luuk van Venrooij",
5
5
  "license": "MIT",
6
6
  "repository": {
package/src/minifier.js CHANGED
@@ -379,8 +379,7 @@ function needsSpaceBetween(left, right) {
379
379
  return false;
380
380
  }
381
381
 
382
- function compress(code) {
383
- const tokens = tokenize(code);
382
+ function compressTokens(tokens) {
384
383
  let out = "";
385
384
 
386
385
  for (let i = 0; i < tokens.length; i++) {
@@ -430,6 +429,10 @@ function compress(code) {
430
429
  return out;
431
430
  }
432
431
 
432
+ function compress(code) {
433
+ return compressTokens(tokenize(code));
434
+ }
435
+
433
436
  function findPrevNonWs(tokens, index) {
434
437
  for (let i = index - 1; i >= 0; i--) {
435
438
  if (tokens[i].type !== "ws" && tokens[i].type !== "comment")
@@ -640,39 +643,154 @@ function shortNameGeneratorFn(occupied = new Set()) {
640
643
 
641
644
  // ── Stage 4: Literal folding ─────────────────────────────────
642
645
 
643
- function foldLiterals(code) {
644
- // Fold patterns like: <number> <op> <number> where both are literal constants
645
- return code.replace(
646
- /\b(\d+(?:\.\d+)?)\s*(\+|-|\*|\/|%)\s*(\d+(?:\.\d+)?)\b/g,
647
- (match, left, op, right) => {
648
- const l = Number(left);
649
- const r = Number(right);
650
- let result;
651
- switch (op) {
652
- case "+":
653
- result = l + r;
654
- break;
655
- case "-":
656
- result = l - r;
657
- break;
658
- case "*":
659
- result = l * r;
660
- break;
661
- case "/":
662
- result = r !== 0 ? l / r : null;
663
- break;
664
- case "%":
665
- result = r !== 0 ? l % r : null;
666
- break;
667
- default:
668
- return match;
646
+ const FOLD_SAFE_PREV = new Set([
647
+ ";",
648
+ "(",
649
+ "[",
650
+ "{",
651
+ ",",
652
+ ":",
653
+ "?",
654
+ "=",
655
+ "+=",
656
+ "-=",
657
+ "*=",
658
+ "/=",
659
+ "%=",
660
+ "&&",
661
+ "||",
662
+ "??",
663
+ "==",
664
+ "!=",
665
+ "===",
666
+ "!==",
667
+ "<",
668
+ "<=",
669
+ ">",
670
+ ">=",
671
+ "return",
672
+ "throw",
673
+ "case",
674
+ "yield",
675
+ "await",
676
+ "=>",
677
+ ]);
678
+
679
+ function _foldBinaryOp(op, l, r) {
680
+ switch (op) {
681
+ case "+":
682
+ return l + r;
683
+ case "-":
684
+ return l - r;
685
+ case "*":
686
+ return l * r;
687
+ case "/":
688
+ return r !== 0 ? l / r : null;
689
+ case "%":
690
+ return r !== 0 ? l % r : null;
691
+ default:
692
+ return null;
693
+ }
694
+ }
695
+
696
+ function _isHigherPrecedenceOp(op, afterOp) {
697
+ if (
698
+ afterOp === "**" ||
699
+ afterOp === "++" ||
700
+ afterOp === "--" ||
701
+ afterOp === "."
702
+ ) {
703
+ return true;
704
+ }
705
+ if (
706
+ (op === "+" || op === "-") &&
707
+ (afterOp === "*" || afterOp === "/" || afterOp === "%")
708
+ ) {
709
+ return true;
710
+ }
711
+ return false;
712
+ }
713
+
714
+ function _canFoldLeft(next) {
715
+ const prevTok = findPrevNonWs(next, next.length);
716
+ return !prevTok || FOLD_SAFE_PREV.has(prevTok.value);
717
+ }
718
+
719
+ function _evaluateFold(tok, opTok, rightTok) {
720
+ const l = Number(tok.value);
721
+ const r = Number(rightTok.value);
722
+ if (!Number.isFinite(l) || !Number.isFinite(r)) return null;
723
+
724
+ let val = _foldBinaryOp(opTok.value, l, r);
725
+ if (val === null || !Number.isFinite(val) || val < 0) return null;
726
+ if (Object.is(val, -0)) val = 0;
727
+
728
+ const s = String(val);
729
+ const origLen = tok.value.length + opTok.value.length + rightTok.value.length;
730
+ return s.length <= origLen ? s : null;
731
+ }
732
+
733
+ function _tryFoldAt(current, i, next) {
734
+ const tok = current[i];
735
+ if (tok.type !== "num" || !_canFoldLeft(next)) return null;
736
+
737
+ const opInfo = nextNonWs(current, i);
738
+ if (opInfo?.tok.type !== "op") return null;
739
+
740
+ const op = opInfo.tok.value;
741
+ if (op !== "+" && op !== "-" && op !== "*" && op !== "/" && op !== "%") {
742
+ return null;
743
+ }
744
+
745
+ const rightInfo = nextNonWs(current, opInfo.idx);
746
+ if (rightInfo?.tok.type !== "num") return null;
747
+
748
+ const afterInfo = nextNonWs(current, rightInfo.idx);
749
+ if (
750
+ afterInfo?.tok.type === "op" &&
751
+ _isHigherPrecedenceOp(op, afterInfo.tok.value)
752
+ ) {
753
+ return null;
754
+ }
755
+
756
+ const folded = _evaluateFold(tok, opInfo.tok, rightInfo.tok);
757
+ if (!folded) return null;
758
+
759
+ next.push({ type: "num", value: folded });
760
+ return rightInfo.idx + 1;
761
+ }
762
+
763
+ function foldTokens(tokens) {
764
+ let changed = true;
765
+ let current = tokens;
766
+ let iterations = 0;
767
+
768
+ while (changed && iterations < 10) {
769
+ changed = false;
770
+ iterations++;
771
+ const next = [];
772
+ let i = 0;
773
+
774
+ while (i < current.length) {
775
+ const nextIdx = _tryFoldAt(current, i, next);
776
+ if (nextIdx !== null) {
777
+ i = nextIdx;
778
+ changed = true;
779
+ } else {
780
+ next.push(current[i]);
781
+ i++;
669
782
  }
670
- if (result === null || !Number.isFinite(result)) return match;
671
- // If result is integer, emit without decimal point
672
- const s = Number.isInteger(result) ? String(result) : String(result);
673
- return s;
674
- },
675
- );
783
+ }
784
+
785
+ current = next;
786
+ }
787
+
788
+ return current;
789
+ }
790
+
791
+ function foldLiterals(code) {
792
+ const tokens = tokenize(code);
793
+ return compressTokens(foldTokens(tokens));
676
794
  }
677
795
 
678
796
  // ── Public API ───────────────────────────────────────────────