solve-engine 2.38.6 → 2.38.7

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 (90) hide show
  1. package/dist/{PackageCompatibility-UpD1nhk6.d.cts → PackageCompatibility-rJfOPkuE.d.cts} +1 -1
  2. package/dist/{PackageCompatibility-BvKJ84Nt.d.ts → PackageCompatibility-th5IHCuQ.d.ts} +1 -1
  3. package/dist/{PackageRegistry-DEFOYdGm.d.cts → PackageRegistry-CDZch8VI.d.cts} +79 -1
  4. package/dist/{PackageRegistry-DIUOXCa1.d.ts → PackageRegistry-yDMyorr3.d.ts} +79 -1
  5. package/dist/{VMBuiltins-CKMK3-LX.d.ts → VMBuiltins-CjuRXAOD.d.ts} +10 -0
  6. package/dist/{VMBuiltins-BdQaT3DC.d.cts → VMBuiltins-DR0PyI_g.d.cts} +10 -0
  7. package/dist/{VMCheckpoints-DRbJOzVW.d.ts → VMCheckpoints-C2REEAxr.d.ts} +1 -1
  8. package/dist/{VMCheckpoints-Bmb47bFF.d.cts → VMCheckpoints-Ch3ElC4X.d.cts} +1 -1
  9. package/dist/chunk-4LSPMT2M.js +3 -0
  10. package/dist/chunk-4LSPMT2M.js.map +1 -0
  11. package/dist/chunk-62JRBFBM.cjs +3 -0
  12. package/dist/chunk-62JRBFBM.cjs.map +1 -0
  13. package/dist/{chunk-MFQUKTLG.cjs → chunk-6ONIPE5L.cjs} +3 -3
  14. package/dist/{chunk-MFQUKTLG.cjs.map → chunk-6ONIPE5L.cjs.map} +1 -1
  15. package/dist/chunk-AAUDBEC2.cjs +5 -0
  16. package/dist/chunk-AAUDBEC2.cjs.map +1 -0
  17. package/dist/{chunk-Z5CAI6QU.cjs → chunk-CNOYGBBV.cjs} +2 -2
  18. package/dist/{chunk-Z5CAI6QU.cjs.map → chunk-CNOYGBBV.cjs.map} +1 -1
  19. package/dist/chunk-JJ4BY6X6.cjs +2 -0
  20. package/dist/chunk-JJ4BY6X6.cjs.map +1 -0
  21. package/dist/chunk-KL2F3YIQ.js +2 -0
  22. package/dist/chunk-KL2F3YIQ.js.map +1 -0
  23. package/dist/{chunk-3KQLJIAN.js → chunk-LZFH7CWS.js} +2 -2
  24. package/dist/{chunk-3KQLJIAN.js.map → chunk-LZFH7CWS.js.map} +1 -1
  25. package/dist/chunk-QFZYS7CY.cjs +2 -0
  26. package/dist/chunk-QFZYS7CY.cjs.map +1 -0
  27. package/dist/chunk-RRI3ZOI3.js +2 -0
  28. package/dist/chunk-RRI3ZOI3.js.map +1 -0
  29. package/dist/chunk-UV6H33IZ.cjs +2 -0
  30. package/dist/chunk-UV6H33IZ.cjs.map +1 -0
  31. package/dist/chunk-WP2CO6BC.js +3 -0
  32. package/dist/chunk-WP2CO6BC.js.map +1 -0
  33. package/dist/chunk-X7556JAZ.js +2 -0
  34. package/dist/chunk-X7556JAZ.js.map +1 -0
  35. package/dist/chunk-Z4KZETIJ.js +5 -0
  36. package/dist/chunk-Z4KZETIJ.js.map +1 -0
  37. package/dist/constants.cjs +1 -1
  38. package/dist/constants.js +1 -1
  39. package/dist/engine.cjs +1 -1
  40. package/dist/engine.d.cts +12 -4
  41. package/dist/engine.d.ts +12 -4
  42. package/dist/engine.js +1 -1
  43. package/dist/engine.worker.cjs +1 -1
  44. package/dist/engine.worker.js +1 -1
  45. package/dist/engine.worker.js.map +1 -1
  46. package/dist/index.cjs +1 -1
  47. package/dist/index.d.cts +4 -4
  48. package/dist/index.d.ts +4 -4
  49. package/dist/index.js +1 -1
  50. package/dist/language.d.cts +3 -3
  51. package/dist/language.d.ts +3 -3
  52. package/dist/packages.cjs +1 -1
  53. package/dist/packages.d.cts +2 -2
  54. package/dist/packages.d.ts +2 -2
  55. package/dist/packages.js +1 -1
  56. package/dist/testing.cjs +2 -2
  57. package/dist/testing.d.cts +3 -3
  58. package/dist/testing.d.ts +3 -3
  59. package/dist/testing.js +1 -1
  60. package/dist/vm.cjs +1 -1
  61. package/dist/vm.d.cts +2 -2
  62. package/dist/vm.d.ts +2 -2
  63. package/dist/vm.js +1 -1
  64. package/dist/worker.cjs +2 -2
  65. package/dist/worker.d.cts +2 -2
  66. package/dist/worker.d.ts +2 -2
  67. package/dist/worker.js +1 -1
  68. package/package.json +1 -1
  69. package/dist/chunk-2NADUGGY.cjs +0 -5
  70. package/dist/chunk-2NADUGGY.cjs.map +0 -1
  71. package/dist/chunk-DTB7KZJR.js +0 -3
  72. package/dist/chunk-DTB7KZJR.js.map +0 -1
  73. package/dist/chunk-GOHW34BB.js +0 -2
  74. package/dist/chunk-GOHW34BB.js.map +0 -1
  75. package/dist/chunk-KSKZAMYD.cjs +0 -2
  76. package/dist/chunk-KSKZAMYD.cjs.map +0 -1
  77. package/dist/chunk-LM66JRCK.js +0 -3
  78. package/dist/chunk-LM66JRCK.js.map +0 -1
  79. package/dist/chunk-M4UC2PB6.cjs +0 -2
  80. package/dist/chunk-M4UC2PB6.cjs.map +0 -1
  81. package/dist/chunk-TJKN466F.js +0 -2
  82. package/dist/chunk-TJKN466F.js.map +0 -1
  83. package/dist/chunk-UY6UIKPD.js +0 -5
  84. package/dist/chunk-UY6UIKPD.js.map +0 -1
  85. package/dist/chunk-WCYAFAUN.cjs +0 -2
  86. package/dist/chunk-WCYAFAUN.cjs.map +0 -1
  87. package/dist/chunk-Y4IHM3PD.js +0 -2
  88. package/dist/chunk-Y4IHM3PD.js.map +0 -1
  89. package/dist/chunk-ZE6JTU23.cjs +0 -3
  90. package/dist/chunk-ZE6JTU23.cjs.map +0 -1
@@ -1,4 +1,4 @@
1
- import { I as IEnginePackage } from './PackageRegistry-DEFOYdGm.cjs';
1
+ import { I as IEnginePackage } from './PackageRegistry-CDZch8VI.cjs';
2
2
 
3
3
  /**
4
4
  * Package load-time compatibility checking, the "detect overlapping
@@ -1,4 +1,4 @@
1
- import { I as IEnginePackage } from './PackageRegistry-DIUOXCa1.js';
1
+ import { I as IEnginePackage } from './PackageRegistry-yDMyorr3.js';
2
2
 
3
3
  /**
4
4
  * Package load-time compatibility checking, the "detect overlapping
@@ -2,7 +2,7 @@ import { a as PrecedenceParser, b as PrefixParselet, I as InfixParselet } from '
2
2
  import { M as MarkdownLineType, L as Lexer, e as TokenCategory, c as LexerVocabulary } from './Lexer-DaWkCu84.cjs';
3
3
  import { IAsyncResolver } from './resolvers.cjs';
4
4
  import { T as TokenFusion, c as TokenNormalizer, a as NormalizerRule } from './TokenNormalizer-D382VSYh.cjs';
5
- import { D as DependencyGraph, V as VM, f as DagSnapshot, g as EngineContext, S as ScopeManager, P as PluginFunctionHandler, A as AsConverter } from './VMBuiltins-BdQaT3DC.cjs';
5
+ import { D as DependencyGraph, V as VM, f as DagSnapshot, g as EngineContext, S as ScopeManager, P as PluginFunctionHandler, A as AsConverter } from './VMBuiltins-DR0PyI_g.cjs';
6
6
  import { V as Value, b as ValueType, D as DatetimeGrain } from './Value-B55Hvn3e.cjs';
7
7
  import { a as BytecodeProgram } from './BytecodeBuilder-DSWKZi4f.cjs';
8
8
  import { C as CalendarBackend } from './CalendarBackend-MdS3Bb4P.cjs';
@@ -261,6 +261,23 @@ declare class DocumentModel {
261
261
  * bottom of a 20k-line document before this fix.
262
262
  */
263
263
  private dirtyLineIds;
264
+ /**
265
+ * Lower-cased category tag to the ids of the lines carrying it, or `null`
266
+ * while nothing has asked.
267
+ *
268
+ * `total of #food` used to walk the whole document looking for `#food`, so a
269
+ * document of members and totals cost one walk per total: D aggregates over
270
+ * N lines is D x N, and a notepad of a few thousand tagged lines took
271
+ * minutes. This turns an aggregate into a lookup of its own members.
272
+ *
273
+ * Built on the first query rather than with the document, so a document with
274
+ * no tags in it, which is most of them, never scans for any. Once built it is
275
+ * kept in step by the four places that change a line's text: {@link setDocument},
276
+ * {@link applyChanges}, {@link editLine} and {@link clear}. Keyed by line id
277
+ * rather than position, so inserting or deleting a line above a tagged one
278
+ * does not touch it.
279
+ */
280
+ private tagIndex;
264
281
  /**
265
282
  * Most lines this model will hold. See `constants/Configuration.ts`'s
266
283
  * `performance.maxDocumentLines`, which is where the default comes from and
@@ -320,6 +337,27 @@ declare class DocumentModel {
320
337
  * Returns true if the text actually changed (hash mismatch).
321
338
  */
322
339
  editLine(lineNumber: number, newText: string): boolean;
340
+ /**
341
+ * The 1-based positions of the lines carrying `#tag`, in document order.
342
+ *
343
+ * What `total of #tag` reads. Case-insensitive, matching how a tag is read
344
+ * on a line, and it names membership only: a line that merely asks about the
345
+ * group (`total of #tag`) is not in it, and neither is a `#heading`.
346
+ *
347
+ * Ascending, because an aggregate reports the first line it cannot read and
348
+ * the line it names has to be the first one in the document, not whichever
349
+ * happened to be indexed first.
350
+ *
351
+ * @param tag - The tag name without its `#`.
352
+ * @returns Its lines' positions, ascending; empty when no line carries it.
353
+ */
354
+ linesCarryingTag(tag: string): number[];
355
+ /** The tag index, built over every line the first time one is asked for. */
356
+ private ensureTagIndex;
357
+ /** Records `lineId` as a member of every group its text joins. */
358
+ private indexTags;
359
+ /** Drops `lineId` from every group the text it used to hold joined. */
360
+ private unindexTags;
323
361
  /**
324
362
  * Get the LineState at the given 1-based line position. O(1).
325
363
  */
@@ -1960,6 +1998,16 @@ declare class ExpressionEngine {
1960
1998
  */
1961
1999
  private batchScanResults;
1962
2000
  private batchParsedLines;
2001
+ /**
2002
+ * Lower-cased category tag to the 1-based lines carrying it, for the batch
2003
+ * pass, or `null` before anything has asked.
2004
+ *
2005
+ * The batch path has no document model to hold this, and the scan it does
2006
+ * have lives only for the pass, so the index does too: built over the scan
2007
+ * on the first aggregate and dropped with it. A document with no aggregate
2008
+ * in it never builds one.
2009
+ */
2010
+ private batchTagIndex;
1963
2011
  /**
1964
2012
  * The context handed to every line of the current pass, its line number
1965
2013
  * set by mutation before each execution. The closures inside read only
@@ -2378,6 +2426,23 @@ declare class ExpressionEngine {
2378
2426
  * still cancels it), or null when nothing was linked.
2379
2427
  */
2380
2428
  private armCancellation;
2429
+ /**
2430
+ * Register a line's edges, including the groups its text joins and asks about.
2431
+ *
2432
+ * A category tag is an edge like any other: a line carrying `#food` writes
2433
+ * that group, and `total of #food` reads it. Registering them here is what
2434
+ * lets an edit to a tagged line dirty only the aggregates over that tag.
2435
+ *
2436
+ * Membership is a property of the text rather than of the bytecode, so it
2437
+ * comes from the same scanner the aggregate itself reads with, which is what
2438
+ * keeps the two from ever disagreeing about what is in a group.
2439
+ *
2440
+ * @param lineNumber - 1-based line the edges belong to.
2441
+ * @param text - The line's expression, which is where its tags are.
2442
+ * @param reads - Variable keys the line reads.
2443
+ * @param writes - Variable keys the line writes.
2444
+ */
2445
+ private registerLineWithTags;
2381
2446
  /**
2382
2447
  * Execute bytecode and handle the result.
2383
2448
  *
@@ -2455,6 +2520,19 @@ declare class ExpressionEngine {
2455
2520
  * bypassing the split→join roundtrip that this method performs.
2456
2521
  */
2457
2522
  evaluateLines(lines: string[]): ParsedLine[];
2523
+ /**
2524
+ * The lines of the batch pass's scan carrying `#tag`, ascending.
2525
+ *
2526
+ * The batch counterpart of `DocumentModel.linesCarryingTag`, over the scan
2527
+ * this pass is walking rather than over a document model. Built once and
2528
+ * read by every aggregate in the pass, which is what makes the pass linear
2529
+ * in the document rather than linear per aggregate.
2530
+ *
2531
+ * @param scan - The pass's scanned lines, indexed from 0 for line 1.
2532
+ * @param tag - The tag name without its `#`.
2533
+ * @returns Its lines' 1-based positions, ascending; empty when none carry it.
2534
+ */
2535
+ private batchLinesCarryingTag;
2458
2536
  /**
2459
2537
  * Process pre-scanned line results into ParsedLine objects.
2460
2538
  *
@@ -2,7 +2,7 @@ import { a as PrecedenceParser, b as PrefixParselet, I as InfixParselet } from '
2
2
  import { M as MarkdownLineType, L as Lexer, e as TokenCategory, c as LexerVocabulary } from './Lexer-DPn5dfCH.js';
3
3
  import { IAsyncResolver } from './resolvers.js';
4
4
  import { T as TokenFusion, c as TokenNormalizer, a as NormalizerRule } from './TokenNormalizer-DAzPp-j1.js';
5
- import { D as DependencyGraph, V as VM, f as DagSnapshot, g as EngineContext, S as ScopeManager, P as PluginFunctionHandler, A as AsConverter } from './VMBuiltins-CKMK3-LX.js';
5
+ import { D as DependencyGraph, V as VM, f as DagSnapshot, g as EngineContext, S as ScopeManager, P as PluginFunctionHandler, A as AsConverter } from './VMBuiltins-CjuRXAOD.js';
6
6
  import { V as Value, b as ValueType, D as DatetimeGrain } from './Value-B55Hvn3e.js';
7
7
  import { a as BytecodeProgram } from './BytecodeBuilder-DSWKZi4f.js';
8
8
  import { C as CalendarBackend } from './CalendarBackend-MdS3Bb4P.js';
@@ -261,6 +261,23 @@ declare class DocumentModel {
261
261
  * bottom of a 20k-line document before this fix.
262
262
  */
263
263
  private dirtyLineIds;
264
+ /**
265
+ * Lower-cased category tag to the ids of the lines carrying it, or `null`
266
+ * while nothing has asked.
267
+ *
268
+ * `total of #food` used to walk the whole document looking for `#food`, so a
269
+ * document of members and totals cost one walk per total: D aggregates over
270
+ * N lines is D x N, and a notepad of a few thousand tagged lines took
271
+ * minutes. This turns an aggregate into a lookup of its own members.
272
+ *
273
+ * Built on the first query rather than with the document, so a document with
274
+ * no tags in it, which is most of them, never scans for any. Once built it is
275
+ * kept in step by the four places that change a line's text: {@link setDocument},
276
+ * {@link applyChanges}, {@link editLine} and {@link clear}. Keyed by line id
277
+ * rather than position, so inserting or deleting a line above a tagged one
278
+ * does not touch it.
279
+ */
280
+ private tagIndex;
264
281
  /**
265
282
  * Most lines this model will hold. See `constants/Configuration.ts`'s
266
283
  * `performance.maxDocumentLines`, which is where the default comes from and
@@ -320,6 +337,27 @@ declare class DocumentModel {
320
337
  * Returns true if the text actually changed (hash mismatch).
321
338
  */
322
339
  editLine(lineNumber: number, newText: string): boolean;
340
+ /**
341
+ * The 1-based positions of the lines carrying `#tag`, in document order.
342
+ *
343
+ * What `total of #tag` reads. Case-insensitive, matching how a tag is read
344
+ * on a line, and it names membership only: a line that merely asks about the
345
+ * group (`total of #tag`) is not in it, and neither is a `#heading`.
346
+ *
347
+ * Ascending, because an aggregate reports the first line it cannot read and
348
+ * the line it names has to be the first one in the document, not whichever
349
+ * happened to be indexed first.
350
+ *
351
+ * @param tag - The tag name without its `#`.
352
+ * @returns Its lines' positions, ascending; empty when no line carries it.
353
+ */
354
+ linesCarryingTag(tag: string): number[];
355
+ /** The tag index, built over every line the first time one is asked for. */
356
+ private ensureTagIndex;
357
+ /** Records `lineId` as a member of every group its text joins. */
358
+ private indexTags;
359
+ /** Drops `lineId` from every group the text it used to hold joined. */
360
+ private unindexTags;
323
361
  /**
324
362
  * Get the LineState at the given 1-based line position. O(1).
325
363
  */
@@ -1960,6 +1998,16 @@ declare class ExpressionEngine {
1960
1998
  */
1961
1999
  private batchScanResults;
1962
2000
  private batchParsedLines;
2001
+ /**
2002
+ * Lower-cased category tag to the 1-based lines carrying it, for the batch
2003
+ * pass, or `null` before anything has asked.
2004
+ *
2005
+ * The batch path has no document model to hold this, and the scan it does
2006
+ * have lives only for the pass, so the index does too: built over the scan
2007
+ * on the first aggregate and dropped with it. A document with no aggregate
2008
+ * in it never builds one.
2009
+ */
2010
+ private batchTagIndex;
1963
2011
  /**
1964
2012
  * The context handed to every line of the current pass, its line number
1965
2013
  * set by mutation before each execution. The closures inside read only
@@ -2378,6 +2426,23 @@ declare class ExpressionEngine {
2378
2426
  * still cancels it), or null when nothing was linked.
2379
2427
  */
2380
2428
  private armCancellation;
2429
+ /**
2430
+ * Register a line's edges, including the groups its text joins and asks about.
2431
+ *
2432
+ * A category tag is an edge like any other: a line carrying `#food` writes
2433
+ * that group, and `total of #food` reads it. Registering them here is what
2434
+ * lets an edit to a tagged line dirty only the aggregates over that tag.
2435
+ *
2436
+ * Membership is a property of the text rather than of the bytecode, so it
2437
+ * comes from the same scanner the aggregate itself reads with, which is what
2438
+ * keeps the two from ever disagreeing about what is in a group.
2439
+ *
2440
+ * @param lineNumber - 1-based line the edges belong to.
2441
+ * @param text - The line's expression, which is where its tags are.
2442
+ * @param reads - Variable keys the line reads.
2443
+ * @param writes - Variable keys the line writes.
2444
+ */
2445
+ private registerLineWithTags;
2381
2446
  /**
2382
2447
  * Execute bytecode and handle the result.
2383
2448
  *
@@ -2455,6 +2520,19 @@ declare class ExpressionEngine {
2455
2520
  * bypassing the split→join roundtrip that this method performs.
2456
2521
  */
2457
2522
  evaluateLines(lines: string[]): ParsedLine[];
2523
+ /**
2524
+ * The lines of the batch pass's scan carrying `#tag`, ascending.
2525
+ *
2526
+ * The batch counterpart of `DocumentModel.linesCarryingTag`, over the scan
2527
+ * this pass is walking rather than over a document model. Built once and
2528
+ * read by every aggregate in the pass, which is what makes the pass linear
2529
+ * in the document rather than linear per aggregate.
2530
+ *
2531
+ * @param scan - The pass's scanned lines, indexed from 0 for line 1.
2532
+ * @param tag - The tag name without its `#`.
2533
+ * @returns Its lines' 1-based positions, ascending; empty when none carry it.
2534
+ */
2535
+ private batchLinesCarryingTag;
2458
2536
  /**
2459
2537
  * Process pre-scanned line results into ParsedLine objects.
2460
2538
  *
@@ -98,6 +98,16 @@ interface LineExecutionContext {
98
98
  calendar?: CalendarBackend;
99
99
  /** Look up another line's cached result by 1-based line number. `undefined` = not evaluated yet (or out of range), distinct from a line that evaluated to an actual `undefined`-like Value, which can't happen (every Value type has a concrete representation). */
100
100
  getLineResult?: (lineNumber: number) => Value | undefined;
101
+ /**
102
+ * The 1-based positions of the lines carrying `#tag`, ascending, or
103
+ * `undefined` when this path keeps no index and the caller should walk the
104
+ * document itself.
105
+ *
106
+ * `total of #tag` used to look at every line of the document, so a notepad
107
+ * of tagged amounts and totals cost aggregates x lines per pass. Both
108
+ * document paths maintain an index instead, and answer from it here.
109
+ */
110
+ getTaggedLines?: (tag: string) => readonly number[] | undefined;
101
111
  /** Whether line `lineNumber` is a blank line or a `#` heading, the stopping condition for "total above"/"sum above"/"average above" aggregation. */
102
112
  isLineBoundary?: (lineNumber: number) => boolean;
103
113
  /**
@@ -98,6 +98,16 @@ interface LineExecutionContext {
98
98
  calendar?: CalendarBackend;
99
99
  /** Look up another line's cached result by 1-based line number. `undefined` = not evaluated yet (or out of range), distinct from a line that evaluated to an actual `undefined`-like Value, which can't happen (every Value type has a concrete representation). */
100
100
  getLineResult?: (lineNumber: number) => Value | undefined;
101
+ /**
102
+ * The 1-based positions of the lines carrying `#tag`, ascending, or
103
+ * `undefined` when this path keeps no index and the caller should walk the
104
+ * document itself.
105
+ *
106
+ * `total of #tag` used to look at every line of the document, so a notepad
107
+ * of tagged amounts and totals cost aggregates x lines per pass. Both
108
+ * document paths maintain an index instead, and answer from it here.
109
+ */
110
+ getTaggedLines?: (tag: string) => readonly number[] | undefined;
101
111
  /** Whether line `lineNumber` is a blank line or a `#` heading, the stopping condition for "total above"/"sum above"/"average above" aggregation. */
102
112
  isLineBoundary?: (lineNumber: number) => boolean;
103
113
  /**
@@ -1,5 +1,5 @@
1
1
  import { V as Value } from './Value-B55Hvn3e.js';
2
- import { V as VM } from './VMBuiltins-CKMK3-LX.js';
2
+ import { V as VM } from './VMBuiltins-CjuRXAOD.js';
3
3
  import { U as UserFunctionDef } from './BytecodeBuilder-DSWKZi4f.js';
4
4
 
5
5
  /**
@@ -1,5 +1,5 @@
1
1
  import { V as Value } from './Value-B55Hvn3e.cjs';
2
- import { V as VM } from './VMBuiltins-BdQaT3DC.cjs';
2
+ import { V as VM } from './VMBuiltins-DR0PyI_g.cjs';
3
3
  import { U as UserFunctionDef } from './BytecodeBuilder-DSWKZi4f.cjs';
4
4
 
5
5
  /**