Commit graph

117 commits

Author SHA1 Message Date
Horizontal42
e148dad463 fix: move misplaced comment in evaluation engine catch block
Moved the informational comment `// a line without a result beats a dead sheet.` to the correct location in the catch block right above `value = null;`, where it accurately describes why we assign null instead of crashing.
2026-08-14 13:39:04 +03:00
Horizontal42
7dfb58b989 share the Decimal PI constant with unitdata.ts
The degree-to-radian ratio computed via native Math.PI/180 instead of
the Decimal PI already defined for evaluator's own trig — moved PI to
types.ts so both can import it without a cycle.
2026-08-12 20:08:28 +03:00
Horizontal42
d4c34bf4af extract baseUnitId in datetime.ts
addToDate and isCalendarUnit both inlined the same prefix-stripping
expression.
2026-08-12 20:07:31 +03:00
Horizontal42
744d6b61d5 document why evalRandom/formatFraction use native float
These two are the only intentional exceptions to the decimal.js-only
rule in the engine; leaving that unstated made them look like bugs
during review.
2026-08-12 20:07:02 +03:00
Horizontal42
0353ae7bf6 extract filterSameDimension/reduceCompatible in AGG_FUNCS
chart/min/max repeated the same same-dimension filter, and sum/avg
repeated the same left-to-right accumulation loop.
2026-08-12 20:06:25 +03:00
Horizontal42
93acfab28c extract asPercentValue in evalPctOp
The percent-or-scalar-as-percent conversion was written out twice
verbatim in the same function.
2026-08-12 20:05:44 +03:00
Horizontal42
573b06e245 reject duplicate ids in addUnit
addUnit() overwrote unitsById unconditionally while its own addPhrase
calls are first-wins, so an extension reusing an existing id silently
corrupted the id->Unit table for anything using that id as a
baseUnitId afterwards. Throw instead.
2026-08-12 20:04:37 +03:00
Horizontal42
3b22d02bf3 drop ambiguous bare currency aliases shared across countries
PRIORITY only disambiguated USD vs TTD's "доллар". "Manat", "FC",
"Som" and "Kwacha" are each shared verbatim between two currencies
(AZN/TMT, CDF/KMF, KGS/UZS, MWK/ZMW) and fell to alphabetical code
order, so e.g. "100 Manat" always silently priced as AZN even when
TMT was meant. Drop the bare alias from the smaller-economy side;
its fuller name still works.
2026-08-12 20:04:33 +03:00
Horizontal42
881fb4809a stop '5 min' from losing the minute unit to the min() aggregate
registerCoreVocab() registers "min" as the aggregate function name
before registerUnits() registers it as the minute abbreviation, and
first-registration-wins means the unit phrase never lands. "5 min"
silently became either plain "5" or got overwritten by a MIN of the
preceding block. Disambiguate right after tokenizing: "min"/"мин"
immediately after a number can only mean minutes.
2026-08-12 20:02:58 +03:00
Horizontal42
741ea16e40 keep evaluateDocument's error boundary around tokenize/parse, not just evaluate
tokenize() and parseLine() ran outside the try/catch, and the parser
has no recursion-depth guard for nested parens. A pathologically
nested line overflowed the stack with an uncaught RangeError, killing
the whole document instead of nulling just that line — the exact
thing evaluateDocument is supposed to prevent.
2026-08-12 20:02:09 +03:00
Horizontal42
aa29c12b37 flush pending autosave before migrating the data folder
save_documents debounces 400ms; migrateDataDir used to fire without
waiting for it, so a save still in flight to the old folder could
land after migrate had already moved documents.json away, silently
recreating it in the abandoned folder and stranding the last edit.
2026-08-12 20:00:26 +03:00
Horizontal42
dad3de70a5
bound migrate_data_dir cleanup to known files, add dialog-verified new_dir 2026-08-09 16:27:08 +03:00
Horizontal42
135ef290df
fix stale drag rects on scroll, drop unused jsdom deps 2026-08-09 16:21:04 +03:00
Horizontal42
d08d807961 fix flaky debounce test: poll with real timers instead of guessing tick count 2026-08-09 16:19:45 +03:00
Horizontal42
59df3a7264
flatten parser into a Pratt parser 2026-08-09 16:00:19 +03:00
Horizontal42
d3731be6ef
add missing evaluation error tests 2026-08-09 15:59:56 +03:00
Horizontal42
55d8401a44
batch historical rates IPC calls with a pooled http client 2026-08-09 15:59:44 +03:00
Horizontal42
bba294c6d5
extract renderDocList helpers 2026-08-09 15:59:19 +03:00
Horizontal42
423d22d462
add evaluator quantity conversion tests 2026-08-09 15:59:13 +03:00
Horizontal42
bcb38c9c1c
split evaluate switch into per-kind helpers 2026-08-09 15:58:53 +03:00
Horizontal42
54c9cc63b0
surface non-EvalError exceptions in evaluation engine 2026-08-09 15:57:35 +03:00
Horizontal42
62ef8cc8cd
assert console availability directly instead of matching an error message 2026-08-09 15:57:33 +03:00
Horizontal42
5554205193
document PctOp usage 2026-08-09 15:57:30 +03:00
Horizontal42
2762e4461c
split extensions load into isolated helpers 2026-08-09 15:57:28 +03:00
Horizontal42
3a657a2d5d
dedupe evaluation logic in Workspace 2026-08-09 15:57:25 +03:00
Horizontal42
edfa55e4dc
extract sparkline SVG rendering into its own module 2026-08-09 15:57:22 +03:00
Horizontal42
a384b98dcb
add isCalendarUnit edge case tests 2026-08-09 15:57:20 +03:00
Horizontal42
8f200bcd61
add engine vocab module tests 2026-08-09 15:57:17 +03:00
Horizontal42
460a12e695
improve date order detection tests with real Intl calls 2026-08-09 15:57:15 +03:00
Horizontal42
dcac3ae425
add registry tests 2026-08-09 15:57:13 +03:00
Horizontal42
6716f1b6da
add coverage for storage utility functions 2026-08-09 15:57:10 +03:00
Horizontal42
b0f6e9e89b run extensions in a quickjs wasm sandbox
replaces new Function() in the main window; per-script and per-call
interrupt deadlines, memory and stack limits, graceful skip if the
wasm module fails to load. csp script-src drops 'unsafe-eval' for
'wasm-unsafe-eval'.
2026-07-29 14:38:28 +03:00
Horizontal42
1a12d75ec6 add regression test for sequence error recovery 2026-07-29 14:14:49 +03:00
Horizontal42
ca6fa6d381 cache findSheetByTitle lookups 2026-07-29 14:14:49 +03:00
Horizontal42
c89242b626 debounce variable highlight scanning in editor 2026-07-29 14:14:49 +03:00
Horizontal42
5ccb46b01c cache sheet results for numeric search 2026-07-29 14:14:49 +03:00
Horizontal42
fd93b00bf5 extract drag-and-drop logic from renderDocList 2026-07-29 14:14:49 +03:00
Horizontal42
8ef2f8b445 extract UI bindings out of initUI 2026-07-29 14:14:49 +03:00
Horizontal42
42f3611dca split evalBin into percent/quantity arithmetic helpers 2026-07-29 14:14:49 +03:00
Horizontal42
d66cad2dcf avoid full split() in titleFromContent 2026-07-29 14:14:48 +03:00
Horizontal42
439eec2795 add tokenizer tests 2026-07-29 14:14:48 +03:00
Horizontal42
6292bbf103 add formatter tests for formatNumber/formatValue 2026-07-29 14:14:48 +03:00
Horizontal42
adea6870fd add parser tests for parseLine 2026-07-29 14:14:48 +03:00
Horizontal42
e70c69df52 add lexer tests for lexLine 2026-07-29 14:14:48 +03:00
Horizontal42
6a88767edf extract evalAgg into an AGG_FUNCS lookup table 2026-07-29 14:14:48 +03:00
Horizontal42
68d7492dba fix modal backdrop-click guard, re-entrancy, and monotonic clock
- Track window focus via performance.now() instead of suppressing all backdrop
  clicks for 300ms after the modal appears. This fixes over-suppression (Ctrl+W
  close-sheet now dismisses on immediate click) while keeping protection for
  genuine stray refocus-clicks (native dialog closing, tray window refocus).
- Serialize concurrent askModal calls via a promise chain so a second call
  queues instead of clobbering the first's handlers (was: hang on concurrent
  modal show).
- Use monotonic performance.now() throughout to avoid clock-jump edge cases
  with Date.now().
2026-07-16 02:42:14 +03:00
Horizontal42
087ee44f12 ignore backdrop click within 300ms of showing a modal
a click that focuses the window lands on the modal backdrop too, so
the update-available prompt after an unattended auto-check could get
dismissed by the very click that brought the window to front, before
it was ever seen
2026-07-16 01:14:52 +03:00
Horizontal42
c1a7254fdf fix arbitrary file write via write_text_file/write_image_file
Both Tauri commands took a raw path string straight from the frontend
and wrote to it with no validation — any code able to call invoke()
(a compromised or malicious extension script, which run with full page
privileges) could write to any path the OS user has access to, not just
one chosen through the save dialog. Move the save-file dialog into the
Rust command itself so the only path ever used is one the native dialog
returned; the frontend now only sends the content to save.
2026-07-08 15:50:13 +03:00
Horizontal42
f2deaa1b94 split lexLine's number/date matching into named helpers
lexLine had grown into one long function trying dates, hex/bin/oct,
grouped numbers, decimals and xrefs inline. Extracted each into a
tryLex* helper with the same fallback order, so the driving loop
reads as a priority list instead of nested ifs.
2026-07-08 15:48:40 +03:00
Horizontal42
a674c66d63 split boot() into initSettings/initDataAndEngine/initUI
Boot had grown into one long function covering settings load, engine
and workspace setup, and all the UI wiring. Split along those natural
phase boundaries; boot() itself is now just the three awaits in order.
2026-07-08 15:46:22 +03:00