@particle-academy/holy-sheet 2.11.0 → 2.11.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.
package/dist/index.d.cts CHANGED
@@ -266,7 +266,7 @@ interface SetMetaOp {
266
266
  }
267
267
 
268
268
  /** This package's own version, pinned to package.json by `version.test.ts`. */
269
- declare const VERSION = "2.11.0";
269
+ declare const VERSION = "2.11.2";
270
270
  type Any$6 = any;
271
271
  /**
272
272
  * Agent — the structured-tool surface for Holy Sheet. Mirrors PHP `Agent`.
@@ -360,7 +360,7 @@ type Any$5 = any;
360
360
  * over `Agent`. Provided for parity / DI ergonomics; most callers use `Agent`.
361
361
  */
362
362
  declare class HolySheet {
363
- static readonly VERSION = "2.11.0";
363
+ static readonly VERSION = "2.11.2";
364
364
  validate(schema: Any$5): ValidationError[];
365
365
  toBytes(schema: Any$5): Uint8Array;
366
366
  write(schema: Any$5, path: string): Promise<WriteResult>;
@@ -649,6 +649,14 @@ declare class Normalizer {
649
649
  private normalizeColumnWidths;
650
650
  private columnFormat;
651
651
  private buildCell;
652
+ /**
653
+ * `explicit`: the value came from an object cell's `value` key. An explicit
654
+ * string is the caller saying "this text, exactly", so it is never coerced
655
+ * to a number: `{value: "+1"}` stays "+1" and `{value: "007"}` stays "007".
656
+ * Only a date/datetime display format still turns a string into a serial,
657
+ * because that conversion is what the format asks for. Bare values keep
658
+ * numeric-string coercion. Mirrors PHP `Normalizer::coerceValue`.
659
+ */
652
660
  private coerceValue;
653
661
  }
654
662
 
@@ -665,10 +673,24 @@ declare class FormulaLinter {
665
673
  * `#REF!` rather than a range of blanks.
666
674
  */
667
675
  private sheetNames;
676
+ /**
677
+ * Why a cell's own formula produced #NAME?, keyed `Sheet!A1`: a syntax
678
+ * error, an unknown function, or a linter fault. A cell with #NAME? and no
679
+ * entry here inherited it from a cell it references.
680
+ */
681
+ private nameCauses;
682
+ /**
683
+ * Greater than 0 while parsing an IF branch that is not taken. The parser
684
+ * evaluates as it goes, so a skipped branch is still PARSED (its syntax
685
+ * errors and unknown functions are reported) but nothing in it is
686
+ * EVALUATED: no operator runs, no cell is read, and every value is null.
687
+ */
688
+ private skipping;
668
689
  lint(schema: unknown): FormulaProblem[];
669
690
  private buildIndex;
670
691
  private isError;
671
692
  private evaluate;
693
+ private describeToken;
672
694
  private tokenize;
673
695
  private peek;
674
696
  private isOp;
@@ -676,8 +698,32 @@ declare class FormulaLinter {
676
698
  private parseConcat;
677
699
  private parseArith;
678
700
  private parseTerm;
701
+ /**
702
+ * `^` binds tighter than `*` and `/` (=2*3^2 is 18) and, as in Excel, is
703
+ * left-associative (=2^3^2 is 64). Negation binds tighter than `^`, so
704
+ * =-2^2 is 4: Excel's order, not mathematics'.
705
+ */
706
+ private parsePower;
679
707
  private parseUnary;
708
+ /**
709
+ * Excel's `%` is a POSTFIX operator that divides by 100: `50%` is 0.5 and
710
+ * `A1%` is A1/100. It binds tighter than `^`, `*` and `/`. There is no
711
+ * binary `%`, so `10%2` leaves a stray `2` and is a syntax error.
712
+ */
713
+ private parsePercent;
680
714
  private parsePrimary;
715
+ /**
716
+ * IF, evaluated lazily as Excel does: `=IF(A2=0,0,1/A2)` with A2 = 0 is 0,
717
+ * not #DIV/0!. Every argument is parsed, so a syntax error or an unknown
718
+ * function anywhere in it is still reported, but only the condition and the
719
+ * branch it selects are evaluated.
720
+ *
721
+ * The order of the verdicts is deliberate. A syntax error anywhere wins,
722
+ * because Excel refuses a formula it cannot parse and computes nothing.
723
+ * Then fewer than two arguments is #VALUE!. Then an error in the condition
724
+ * propagates, and neither branch is evaluated.
725
+ */
726
+ private parseIf;
681
727
  private resolveRefOrRange;
682
728
  private cleanRef;
683
729
  /**
@@ -691,6 +737,12 @@ declare class FormulaLinter {
691
737
  private coerceNumber;
692
738
  private coerceString;
693
739
  private compare;
740
+ /**
741
+ * Excel's comparison. An error on either side propagates. Otherwise the
742
+ * types rank number < text < logical, so ="5">9 is TRUE: numeric TEXT is
743
+ * text, never a number. Text compares without regard to case. A blank
744
+ * takes the other side's type (0, "" or FALSE); two blanks are equal.
745
+ */
694
746
  private cmpVal;
695
747
  private callFunction;
696
748
  private flatten;
@@ -698,8 +750,23 @@ declare class FormulaLinter {
698
750
  private maybeNum;
699
751
  private avg;
700
752
  private minMax;
701
- private ifFn;
753
+ /**
754
+ * Excel's reading of an IF condition: an error propagates, a blank is
755
+ * FALSE, a number is TRUE unless it is 0, and text is TRUE or FALSE only
756
+ * when it spells one of them (in any case). Any other text, "" included,
757
+ * is #VALUE!.
758
+ */
759
+ private toLogical;
702
760
  private hint;
761
+ /**
762
+ * #NAME? has three causes in this formula, plus inheritance, and each hint
763
+ * says which one it is. A syntax error used to be told it "references an
764
+ * unknown function", and an agent went hunting for a function that was fine.
765
+ * The texts are byte-identical to PHP's and Python's: see PHP
766
+ * `FormulaLinter::hintName` for why a syntax error keeps the #NAME? label.
767
+ */
768
+ private hintName;
769
+ private hintInheritedName;
703
770
  private hintRef;
704
771
  private hintValue;
705
772
  }
package/dist/index.d.ts CHANGED
@@ -266,7 +266,7 @@ interface SetMetaOp {
266
266
  }
267
267
 
268
268
  /** This package's own version, pinned to package.json by `version.test.ts`. */
269
- declare const VERSION = "2.11.0";
269
+ declare const VERSION = "2.11.2";
270
270
  type Any$6 = any;
271
271
  /**
272
272
  * Agent — the structured-tool surface for Holy Sheet. Mirrors PHP `Agent`.
@@ -360,7 +360,7 @@ type Any$5 = any;
360
360
  * over `Agent`. Provided for parity / DI ergonomics; most callers use `Agent`.
361
361
  */
362
362
  declare class HolySheet {
363
- static readonly VERSION = "2.11.0";
363
+ static readonly VERSION = "2.11.2";
364
364
  validate(schema: Any$5): ValidationError[];
365
365
  toBytes(schema: Any$5): Uint8Array;
366
366
  write(schema: Any$5, path: string): Promise<WriteResult>;
@@ -649,6 +649,14 @@ declare class Normalizer {
649
649
  private normalizeColumnWidths;
650
650
  private columnFormat;
651
651
  private buildCell;
652
+ /**
653
+ * `explicit`: the value came from an object cell's `value` key. An explicit
654
+ * string is the caller saying "this text, exactly", so it is never coerced
655
+ * to a number: `{value: "+1"}` stays "+1" and `{value: "007"}` stays "007".
656
+ * Only a date/datetime display format still turns a string into a serial,
657
+ * because that conversion is what the format asks for. Bare values keep
658
+ * numeric-string coercion. Mirrors PHP `Normalizer::coerceValue`.
659
+ */
652
660
  private coerceValue;
653
661
  }
654
662
 
@@ -665,10 +673,24 @@ declare class FormulaLinter {
665
673
  * `#REF!` rather than a range of blanks.
666
674
  */
667
675
  private sheetNames;
676
+ /**
677
+ * Why a cell's own formula produced #NAME?, keyed `Sheet!A1`: a syntax
678
+ * error, an unknown function, or a linter fault. A cell with #NAME? and no
679
+ * entry here inherited it from a cell it references.
680
+ */
681
+ private nameCauses;
682
+ /**
683
+ * Greater than 0 while parsing an IF branch that is not taken. The parser
684
+ * evaluates as it goes, so a skipped branch is still PARSED (its syntax
685
+ * errors and unknown functions are reported) but nothing in it is
686
+ * EVALUATED: no operator runs, no cell is read, and every value is null.
687
+ */
688
+ private skipping;
668
689
  lint(schema: unknown): FormulaProblem[];
669
690
  private buildIndex;
670
691
  private isError;
671
692
  private evaluate;
693
+ private describeToken;
672
694
  private tokenize;
673
695
  private peek;
674
696
  private isOp;
@@ -676,8 +698,32 @@ declare class FormulaLinter {
676
698
  private parseConcat;
677
699
  private parseArith;
678
700
  private parseTerm;
701
+ /**
702
+ * `^` binds tighter than `*` and `/` (=2*3^2 is 18) and, as in Excel, is
703
+ * left-associative (=2^3^2 is 64). Negation binds tighter than `^`, so
704
+ * =-2^2 is 4: Excel's order, not mathematics'.
705
+ */
706
+ private parsePower;
679
707
  private parseUnary;
708
+ /**
709
+ * Excel's `%` is a POSTFIX operator that divides by 100: `50%` is 0.5 and
710
+ * `A1%` is A1/100. It binds tighter than `^`, `*` and `/`. There is no
711
+ * binary `%`, so `10%2` leaves a stray `2` and is a syntax error.
712
+ */
713
+ private parsePercent;
680
714
  private parsePrimary;
715
+ /**
716
+ * IF, evaluated lazily as Excel does: `=IF(A2=0,0,1/A2)` with A2 = 0 is 0,
717
+ * not #DIV/0!. Every argument is parsed, so a syntax error or an unknown
718
+ * function anywhere in it is still reported, but only the condition and the
719
+ * branch it selects are evaluated.
720
+ *
721
+ * The order of the verdicts is deliberate. A syntax error anywhere wins,
722
+ * because Excel refuses a formula it cannot parse and computes nothing.
723
+ * Then fewer than two arguments is #VALUE!. Then an error in the condition
724
+ * propagates, and neither branch is evaluated.
725
+ */
726
+ private parseIf;
681
727
  private resolveRefOrRange;
682
728
  private cleanRef;
683
729
  /**
@@ -691,6 +737,12 @@ declare class FormulaLinter {
691
737
  private coerceNumber;
692
738
  private coerceString;
693
739
  private compare;
740
+ /**
741
+ * Excel's comparison. An error on either side propagates. Otherwise the
742
+ * types rank number < text < logical, so ="5">9 is TRUE: numeric TEXT is
743
+ * text, never a number. Text compares without regard to case. A blank
744
+ * takes the other side's type (0, "" or FALSE); two blanks are equal.
745
+ */
694
746
  private cmpVal;
695
747
  private callFunction;
696
748
  private flatten;
@@ -698,8 +750,23 @@ declare class FormulaLinter {
698
750
  private maybeNum;
699
751
  private avg;
700
752
  private minMax;
701
- private ifFn;
753
+ /**
754
+ * Excel's reading of an IF condition: an error propagates, a blank is
755
+ * FALSE, a number is TRUE unless it is 0, and text is TRUE or FALSE only
756
+ * when it spells one of them (in any case). Any other text, "" included,
757
+ * is #VALUE!.
758
+ */
759
+ private toLogical;
702
760
  private hint;
761
+ /**
762
+ * #NAME? has three causes in this formula, plus inheritance, and each hint
763
+ * says which one it is. A syntax error used to be told it "references an
764
+ * unknown function", and an agent went hunting for a function that was fine.
765
+ * The texts are byte-identical to PHP's and Python's: see PHP
766
+ * `FormulaLinter::hintName` for why a syntax error keeps the #NAME? label.
767
+ */
768
+ private hintName;
769
+ private hintInheritedName;
703
770
  private hintRef;
704
771
  private hintValue;
705
772
  }
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { Agent, VERSION } from './chunk-OL6E7DE5.js';
2
- export { Agent, ArchiveRefused, ArrayBuilder, CellAddress, CsvBuilder, FormatSniffer, FormulaLinter, Inference, Normalizer, OdsReader, OfficeTemplateRefused, Repairer, SchemaException, SheetDiff, SheetOpSchema, SheetReducer, Theme, UnsupportedFormatException, VERSION, Validator, XlsxReader, XlsxWriter, unzipSync, zipSync } from './chunk-OL6E7DE5.js';
1
+ import { Agent, VERSION } from './chunk-Y32UXRQ6.js';
2
+ export { Agent, ArchiveRefused, ArrayBuilder, CellAddress, CsvBuilder, FormatSniffer, FormulaLinter, Inference, Normalizer, OdsReader, OfficeTemplateRefused, Repairer, SchemaException, SheetDiff, SheetOpSchema, SheetReducer, Theme, UnsupportedFormatException, VERSION, Validator, XlsxReader, XlsxWriter, unzipSync, zipSync } from './chunk-Y32UXRQ6.js';
3
3
 
4
4
  // src/holy-sheet.ts
5
5
  var HolySheet = class {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@particle-academy/holy-sheet",
3
- "version": "2.11.0",
3
+ "version": "2.11.2",
4
4
  "description": "Zero-dependency, isomorphic xlsx writer + reader + formula linter for agentic document creation. The Node/TypeScript mirror of the PHP particle-academy/holy-sheet (feature-parity with PHP 1.2.0).",
5
5
  "repository": {
6
6
  "type": "git",