littlewing 0.6.0 → 0.7.0

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/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 brielov
3
+ Copyright (c) 2025 Gabriel Vaquer <brielov@icloud.com>
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -12,7 +12,7 @@ execute("2 + 3 * 4"); // → 14
12
12
  execute("radius = 5; area = 3.14159 * radius ^ 2", defaultContext); // → 78.54
13
13
 
14
14
  // Date arithmetic with timestamps
15
- execute("deadline = now() + days(7)", defaultContext); // → timestamp 7 days from now
15
+ execute("deadline = NOW() + FROM_DAYS(7)", defaultContext); // → timestamp 7 days from now
16
16
 
17
17
  // Conditional logic
18
18
  execute("score = 85; grade = score >= 90 ? 100 : 90", {
@@ -23,12 +23,13 @@ execute("score = 85; grade = score >= 90 ? 100 : 90", {
23
23
  ## Features
24
24
 
25
25
  - **Numbers-only** - Every value is a number. Simple, predictable, fast.
26
- - **Zero dependencies** - 5.20 KB gzipped, perfect for browser bundles
26
+ - **Zero dependencies** - 6.15 KB gzipped, perfect for browser bundles
27
27
  - **O(n) performance** - Linear time parsing and execution
28
28
  - **Safe evaluation** - No eval(), no code generation, no security risks
29
29
  - **Timestamp arithmetic** - Built-in date/time functions using numeric timestamps
30
30
  - **Extensible** - Add custom functions and variables via context
31
31
  - **Type-safe** - Full TypeScript support with strict types
32
+ - **99%+ test coverage** - 276 tests with 99.39% function coverage, 99.56% line coverage
32
33
 
33
34
  ## Installation
34
35
 
@@ -70,22 +71,33 @@ execute("age >= 18 ? 100 : 0", { variables: { age: 21 } }); // → 100
70
71
  import { execute, defaultContext } from "littlewing";
71
72
 
72
73
  // Math functions
73
- execute("abs(-42)", defaultContext); // → 42
74
- execute("sqrt(16)", defaultContext); // → 4
75
- execute("max(3, 7, 2)", defaultContext); // → 7
74
+ execute("ABS(-42)", defaultContext); // → 42
75
+ execute("SQRT(16)", defaultContext); // → 4
76
+ execute("MAX(3, 7, 2)", defaultContext); // → 7
76
77
 
77
78
  // Current timestamp
78
- execute("now()", defaultContext); // → 1704067200000
79
+ execute("NOW()", defaultContext); // → 1704067200000
79
80
 
80
81
  // Date arithmetic
81
- execute("now() + hours(2)", defaultContext); // → timestamp 2 hours from now
82
- execute("tomorrow = now() + days(1)", defaultContext); // → tomorrow's timestamp
82
+ execute("NOW() + FROM_HOURS(2)", defaultContext); // → timestamp 2 hours from now
83
+ execute("tomorrow = NOW() + FROM_DAYS(1)", defaultContext); // → tomorrow's timestamp
83
84
 
84
85
  // Extract date components
85
86
  const ctx = { ...defaultContext, variables: { ts: Date.now() } };
86
- execute("year(ts)", ctx); // → 2024
87
- execute("month(ts)", ctx); // → 11
88
- execute("day(ts)", ctx); // → 6
87
+ execute("GET_YEAR(ts)", ctx); // → 2024
88
+ execute("GET_MONTH(ts)", ctx); // → 11
89
+ execute("GET_DAY(ts)", ctx); // → 6
90
+
91
+ // Calculate time differences
92
+ const ts1 = Date.now();
93
+ const ts2 = ts1 + 1000 * 60 * 60 * 5; // 5 hours later
94
+ const context = { ...defaultContext, variables: { ts1, ts2 } };
95
+ execute("DIFFERENCE_IN_HOURS(ts1, ts2)", context); // → 5
96
+
97
+ // Date arithmetic and comparisons
98
+ execute("ADD_DAYS(NOW(), 7)", defaultContext); // → 7 days from now
99
+ execute("START_OF_DAY(NOW())", defaultContext); // → today at 00:00:00.000
100
+ execute("IS_WEEKEND(NOW())", defaultContext); // → 1 if today is Sat/Sun, else 0
89
101
  ```
90
102
 
91
103
  ### Custom Functions and Variables
@@ -150,7 +162,7 @@ Execute an expression and return the result.
150
162
 
151
163
  ```typescript
152
164
  execute("2 + 2"); // → 4
153
- execute("abs(-5)", { functions: { abs: Math.abs } }); // → 5
165
+ execute("ABS(-5)", { functions: { ABS: Math.abs } }); // → 5
154
166
  ```
155
167
 
156
168
  #### `parseSource(source: string): ASTNode`
@@ -197,11 +209,23 @@ interface ExecutionContext {
197
209
 
198
210
  The `defaultContext` includes these built-in functions:
199
211
 
200
- **Math:** `abs`, `ceil`, `floor`, `round`, `sqrt`, `min`, `max`, `sin`, `cos`, `tan`, `log`, `log10`, `exp`
212
+ **Math:** `ABS`, `CEIL`, `FLOOR`, `ROUND`, `SQRT`, `MIN`, `MAX`, `SIN`, `COS`, `TAN`, `LOG`, `LOG10`, `EXP`
201
213
 
202
- **Time:** `now`, `timestamp`, `milliseconds`, `seconds`, `minutes`, `hours`, `days`, `weeks`
214
+ **Timestamps:** `NOW`, `DATE`
203
215
 
204
- **Date components:** `year`, `month`, `day`, `hour`, `minute`, `second`, `weekday`
216
+ **Time converters (to milliseconds):** `FROM_SECONDS`, `FROM_MINUTES`, `FROM_HOURS`, `FROM_DAYS`, `FROM_WEEKS`, `FROM_MONTHS`, `FROM_YEARS`
217
+
218
+ **Date component extractors:** `GET_YEAR`, `GET_MONTH`, `GET_DAY`, `GET_HOUR`, `GET_MINUTE`, `GET_SECOND`, `GET_WEEKDAY`, `GET_MILLISECOND`, `GET_DAY_OF_YEAR`, `GET_QUARTER`
219
+
220
+ **Time differences (always positive):** `DIFFERENCE_IN_SECONDS`, `DIFFERENCE_IN_MINUTES`, `DIFFERENCE_IN_HOURS`, `DIFFERENCE_IN_DAYS`, `DIFFERENCE_IN_WEEKS`
221
+
222
+ **Start/End of period:** `START_OF_DAY`, `END_OF_DAY`, `START_OF_WEEK`, `START_OF_MONTH`, `END_OF_MONTH`, `START_OF_YEAR`, `END_OF_YEAR`, `START_OF_QUARTER`
223
+
224
+ **Date arithmetic:** `ADD_DAYS`, `ADD_MONTHS`, `ADD_YEARS`
225
+
226
+ **Date comparisons:** `IS_BEFORE`, `IS_AFTER`, `IS_SAME_DAY`, `IS_WEEKEND`, `IS_LEAP_YEAR`
227
+
228
+ **Unix time:** `TO_UNIX_SECONDS`, `FROM_UNIX_SECONDS`
205
229
 
206
230
  ## Use Cases
207
231
 
package/dist/index.d.ts CHANGED
@@ -294,28 +294,217 @@ declare class CodeGenerator {
294
294
  * Generate source code from an AST node
295
295
  */
296
296
  declare function generate(node: ASTNode): string;
297
+ declare namespace exports_date_utils {
298
+ export { TO_UNIX_SECONDS, START_OF_YEAR, START_OF_WEEK, START_OF_QUARTER, START_OF_MONTH, START_OF_DAY, NOW, IS_WEEKEND, IS_SAME_DAY, IS_LEAP_YEAR, IS_BEFORE, IS_AFTER, GET_YEAR, GET_WEEKDAY, GET_SECOND, GET_QUARTER, GET_MONTH, GET_MINUTE, GET_MILLISECOND, GET_HOUR, GET_DAY_OF_YEAR, GET_DAY, FROM_YEARS, FROM_WEEKS, FROM_UNIX_SECONDS, FROM_SECONDS, FROM_MONTHS, FROM_MINUTES, FROM_HOURS, FROM_DAYS, END_OF_YEAR, END_OF_MONTH, END_OF_DAY, DIFFERENCE_IN_WEEKS, DIFFERENCE_IN_SECONDS, DIFFERENCE_IN_MINUTES, DIFFERENCE_IN_HOURS, DIFFERENCE_IN_DAYS, DATE, ADD_YEARS, ADD_MONTHS, ADD_DAYS };
299
+ }
300
+ /**
301
+ * Date utility functions for working with timestamps
302
+ * All functions work with milliseconds since Unix epoch (numbers only)
303
+ */
304
+ /**
305
+ * Get current timestamp (milliseconds since Unix epoch)
306
+ */
307
+ declare const NOW: () => number;
308
+ /**
309
+ * Create timestamp from date components
310
+ * Year is required, all other parameters default to minimum values
311
+ * Month is 1-based (1 = January, 12 = December)
312
+ */
313
+ declare const DATE: (year: number, month?: number, day?: number, hour?: number, minute?: number, second?: number) => number;
314
+ /**
315
+ * Convert seconds to milliseconds
316
+ */
317
+ declare const FROM_SECONDS: (s: number) => number;
318
+ /**
319
+ * Convert minutes to milliseconds
320
+ */
321
+ declare const FROM_MINUTES: (m: number) => number;
322
+ /**
323
+ * Convert hours to milliseconds
324
+ */
325
+ declare const FROM_HOURS: (h: number) => number;
326
+ /**
327
+ * Convert days to milliseconds
328
+ */
329
+ declare const FROM_DAYS: (d: number) => number;
330
+ /**
331
+ * Convert weeks to milliseconds
332
+ */
333
+ declare const FROM_WEEKS: (w: number) => number;
334
+ /**
335
+ * Convert months to milliseconds (approximate: 30 days per month)
336
+ */
337
+ declare const FROM_MONTHS: (months: number) => number;
338
+ /**
339
+ * Convert years to milliseconds (approximate: 365 days per year)
340
+ */
341
+ declare const FROM_YEARS: (years: number) => number;
342
+ /**
343
+ * Get the year from a timestamp
344
+ */
345
+ declare const GET_YEAR: (timestamp: number) => number;
346
+ /**
347
+ * Get the month from a timestamp (1-based: 1 = January, 12 = December)
348
+ */
349
+ declare const GET_MONTH: (timestamp: number) => number;
350
+ /**
351
+ * Get the day of month from a timestamp (1-31)
352
+ */
353
+ declare const GET_DAY: (timestamp: number) => number;
354
+ /**
355
+ * Get the hour from a timestamp (0-23)
356
+ */
357
+ declare const GET_HOUR: (timestamp: number) => number;
358
+ /**
359
+ * Get the minute from a timestamp (0-59)
360
+ */
361
+ declare const GET_MINUTE: (timestamp: number) => number;
362
+ /**
363
+ * Get the second from a timestamp (0-59)
364
+ */
365
+ declare const GET_SECOND: (timestamp: number) => number;
366
+ /**
367
+ * Get the millisecond component from a timestamp (0-999)
368
+ */
369
+ declare const GET_MILLISECOND: (timestamp: number) => number;
370
+ /**
371
+ * Get the day of week from a timestamp (0 = Sunday, 6 = Saturday)
372
+ */
373
+ declare const GET_WEEKDAY: (timestamp: number) => number;
374
+ /**
375
+ * Get the day of year (1-366) from a timestamp
376
+ */
377
+ declare const GET_DAY_OF_YEAR: (timestamp: number) => number;
378
+ /**
379
+ * Get the quarter (1-4) from a timestamp
380
+ */
381
+ declare const GET_QUARTER: (timestamp: number) => number;
382
+ /**
383
+ * Get the absolute difference between two timestamps in seconds
384
+ */
385
+ declare const DIFFERENCE_IN_SECONDS: (ts1: number, ts2: number) => number;
386
+ /**
387
+ * Get the absolute difference between two timestamps in minutes
388
+ */
389
+ declare const DIFFERENCE_IN_MINUTES: (ts1: number, ts2: number) => number;
297
390
  /**
298
- * Default execution context with common Math functions and timestamp utilities
391
+ * Get the absolute difference between two timestamps in hours
392
+ */
393
+ declare const DIFFERENCE_IN_HOURS: (ts1: number, ts2: number) => number;
394
+ /**
395
+ * Get the absolute difference between two timestamps in days
396
+ */
397
+ declare const DIFFERENCE_IN_DAYS: (ts1: number, ts2: number) => number;
398
+ /**
399
+ * Get the absolute difference between two timestamps in weeks
400
+ */
401
+ declare const DIFFERENCE_IN_WEEKS: (ts1: number, ts2: number) => number;
402
+ /**
403
+ * Get the start of day (00:00:00.000) for a given timestamp
404
+ */
405
+ declare const START_OF_DAY: (timestamp: number) => number;
406
+ /**
407
+ * Get the end of day (23:59:59.999) for a given timestamp
408
+ */
409
+ declare const END_OF_DAY: (timestamp: number) => number;
410
+ /**
411
+ * Get the start of week (Sunday at 00:00:00.000) for a given timestamp
412
+ */
413
+ declare const START_OF_WEEK: (timestamp: number) => number;
414
+ /**
415
+ * Get the start of month (1st day at 00:00:00.000) for a given timestamp
416
+ */
417
+ declare const START_OF_MONTH: (timestamp: number) => number;
418
+ /**
419
+ * Get the end of month (last day at 23:59:59.999) for a given timestamp
420
+ */
421
+ declare const END_OF_MONTH: (timestamp: number) => number;
422
+ /**
423
+ * Get the start of year (Jan 1st at 00:00:00.000) for a given timestamp
424
+ */
425
+ declare const START_OF_YEAR: (timestamp: number) => number;
426
+ /**
427
+ * Get the end of year (Dec 31st at 23:59:59.999) for a given timestamp
428
+ */
429
+ declare const END_OF_YEAR: (timestamp: number) => number;
430
+ /**
431
+ * Add days to a timestamp
432
+ */
433
+ declare const ADD_DAYS: (timestamp: number, days: number) => number;
434
+ /**
435
+ * Add months to a timestamp (handles variable month lengths correctly)
436
+ */
437
+ declare const ADD_MONTHS: (timestamp: number, months: number) => number;
438
+ /**
439
+ * Add years to a timestamp
440
+ */
441
+ declare const ADD_YEARS: (timestamp: number, years: number) => number;
442
+ /**
443
+ * Check if ts1 is before ts2
444
+ * Returns 1 if true, 0 if false
445
+ */
446
+ declare const IS_BEFORE: (ts1: number, ts2: number) => number;
447
+ /**
448
+ * Check if ts1 is after ts2
449
+ * Returns 1 if true, 0 if false
450
+ */
451
+ declare const IS_AFTER: (ts1: number, ts2: number) => number;
452
+ /**
453
+ * Check if two timestamps are on the same calendar day
454
+ * Returns 1 if true, 0 if false
455
+ */
456
+ declare const IS_SAME_DAY: (ts1: number, ts2: number) => number;
457
+ /**
458
+ * Check if timestamp falls on a weekend (Saturday or Sunday)
459
+ * Returns 1 if true, 0 if false
460
+ */
461
+ declare const IS_WEEKEND: (timestamp: number) => number;
462
+ /**
463
+ * Check if timestamp is in a leap year
464
+ * Returns 1 if true, 0 if false
465
+ */
466
+ declare const IS_LEAP_YEAR: (timestamp: number) => number;
467
+ /**
468
+ * Get the start of quarter for a given timestamp
469
+ */
470
+ declare const START_OF_QUARTER: (timestamp: number) => number;
471
+ /**
472
+ * Convert millisecond timestamp to Unix seconds
473
+ */
474
+ declare const TO_UNIX_SECONDS: (timestamp: number) => number;
475
+ /**
476
+ * Convert Unix seconds to millisecond timestamp
477
+ */
478
+ declare const FROM_UNIX_SECONDS: (seconds: number) => number;
479
+ /**
480
+ * Default execution context with common Math functions and date/time utilities
299
481
  * Users can use this as-is or spread it into their own context
300
482
  *
483
+ * All functions use UPPERCASE naming convention to avoid collisions with user variables.
301
484
  * All date-related functions work with timestamps (milliseconds since Unix epoch)
302
485
  * to maintain the language's numbers-only type system.
303
486
  *
304
487
  * @example
305
488
  * // Use as-is
306
- * execute('abs(-5)', defaultContext)
489
+ * execute('ABS(-5)', defaultContext)
307
490
  *
308
491
  * @example
309
492
  * // Spread into custom context
310
- * execute('now() + minutes(5)', {
493
+ * execute('NOW() + FROM_MINUTES(5)', {
311
494
  * ...defaultContext,
312
495
  * variables: { customVar: 42 }
313
496
  * })
314
497
  *
315
498
  * @example
316
499
  * // Work with timestamps
317
- * const result = execute('now() + days(7)', defaultContext)
500
+ * const result = execute('NOW() + FROM_DAYS(7)', defaultContext)
318
501
  * const futureDate = new Date(result) // Convert back to Date if needed
502
+ *
503
+ * @example
504
+ * // Calculate time differences
505
+ * const ts1 = Date.now()
506
+ * const ts2 = ts1 + 1000 * 60 * 60 * 3 // 3 hours later
507
+ * execute('DIFFERENCE_IN_HOURS(ts1, ts2)', { ...defaultContext, variables: { ts1, ts2 } })
319
508
  */
320
509
  declare const defaultContext: ExecutionContext;
321
510
  /**
@@ -493,4 +682,4 @@ declare class Parser {
493
682
  * @returns Parsed AST
494
683
  */
495
684
  declare function parseSource(source: string): ASTNode;
496
- export { parseSource, optimize, isUnaryOp, isProgram, isNumberLiteral, isIdentifier, isFunctionCall, isConditionalExpression, isBinaryOp, isAssignment, generate, execute, defaultContext, exports_ast as ast, TokenType, Token, RuntimeValue, Parser, Lexer, Executor, ExecutionContext, CodeGenerator, ASTNode };
685
+ export { parseSource, optimize, isUnaryOp, isProgram, isNumberLiteral, isIdentifier, isFunctionCall, isConditionalExpression, isBinaryOp, isAssignment, generate, execute, defaultContext, exports_date_utils as dateUtils, exports_ast as ast, UnaryOp, TokenType, Token, RuntimeValue, Program, Parser, Operator, NumberLiteral, Lexer, Identifier, FunctionCall, Executor, ExecutionContext, ConditionalExpression, CodeGenerator, BinaryOp, Assignment, ASTNode };
package/dist/index.js CHANGED
@@ -373,37 +373,187 @@ function generate(node) {
373
373
  const generator = new CodeGenerator;
374
374
  return generator.generate(node);
375
375
  }
376
+ // src/date-utils.ts
377
+ var exports_date_utils = {};
378
+ __export(exports_date_utils, {
379
+ TO_UNIX_SECONDS: () => TO_UNIX_SECONDS,
380
+ START_OF_YEAR: () => START_OF_YEAR,
381
+ START_OF_WEEK: () => START_OF_WEEK,
382
+ START_OF_QUARTER: () => START_OF_QUARTER,
383
+ START_OF_MONTH: () => START_OF_MONTH,
384
+ START_OF_DAY: () => START_OF_DAY,
385
+ NOW: () => NOW,
386
+ IS_WEEKEND: () => IS_WEEKEND,
387
+ IS_SAME_DAY: () => IS_SAME_DAY,
388
+ IS_LEAP_YEAR: () => IS_LEAP_YEAR,
389
+ IS_BEFORE: () => IS_BEFORE,
390
+ IS_AFTER: () => IS_AFTER,
391
+ GET_YEAR: () => GET_YEAR,
392
+ GET_WEEKDAY: () => GET_WEEKDAY,
393
+ GET_SECOND: () => GET_SECOND,
394
+ GET_QUARTER: () => GET_QUARTER,
395
+ GET_MONTH: () => GET_MONTH,
396
+ GET_MINUTE: () => GET_MINUTE,
397
+ GET_MILLISECOND: () => GET_MILLISECOND,
398
+ GET_HOUR: () => GET_HOUR,
399
+ GET_DAY_OF_YEAR: () => GET_DAY_OF_YEAR,
400
+ GET_DAY: () => GET_DAY,
401
+ FROM_YEARS: () => FROM_YEARS,
402
+ FROM_WEEKS: () => FROM_WEEKS,
403
+ FROM_UNIX_SECONDS: () => FROM_UNIX_SECONDS,
404
+ FROM_SECONDS: () => FROM_SECONDS,
405
+ FROM_MONTHS: () => FROM_MONTHS,
406
+ FROM_MINUTES: () => FROM_MINUTES,
407
+ FROM_HOURS: () => FROM_HOURS,
408
+ FROM_DAYS: () => FROM_DAYS,
409
+ END_OF_YEAR: () => END_OF_YEAR,
410
+ END_OF_MONTH: () => END_OF_MONTH,
411
+ END_OF_DAY: () => END_OF_DAY,
412
+ DIFFERENCE_IN_WEEKS: () => DIFFERENCE_IN_WEEKS,
413
+ DIFFERENCE_IN_SECONDS: () => DIFFERENCE_IN_SECONDS,
414
+ DIFFERENCE_IN_MINUTES: () => DIFFERENCE_IN_MINUTES,
415
+ DIFFERENCE_IN_HOURS: () => DIFFERENCE_IN_HOURS,
416
+ DIFFERENCE_IN_DAYS: () => DIFFERENCE_IN_DAYS,
417
+ DATE: () => DATE,
418
+ ADD_YEARS: () => ADD_YEARS,
419
+ ADD_MONTHS: () => ADD_MONTHS,
420
+ ADD_DAYS: () => ADD_DAYS
421
+ });
422
+ var NOW = () => Date.now();
423
+ var DATE = (year, month = 1, day = 1, hour = 0, minute = 0, second = 0) => new Date(year, month - 1, day, hour, minute, second).getTime();
424
+ var FROM_SECONDS = (s) => s * 1000;
425
+ var FROM_MINUTES = (m) => m * 60 * 1000;
426
+ var FROM_HOURS = (h) => h * 60 * 60 * 1000;
427
+ var FROM_DAYS = (d) => d * 24 * 60 * 60 * 1000;
428
+ var FROM_WEEKS = (w) => w * 7 * 24 * 60 * 60 * 1000;
429
+ var FROM_MONTHS = (months) => months * 30 * 24 * 60 * 60 * 1000;
430
+ var FROM_YEARS = (years) => years * 365 * 24 * 60 * 60 * 1000;
431
+ var GET_YEAR = (timestamp) => new Date(timestamp).getFullYear();
432
+ var GET_MONTH = (timestamp) => new Date(timestamp).getMonth() + 1;
433
+ var GET_DAY = (timestamp) => new Date(timestamp).getDate();
434
+ var GET_HOUR = (timestamp) => new Date(timestamp).getHours();
435
+ var GET_MINUTE = (timestamp) => new Date(timestamp).getMinutes();
436
+ var GET_SECOND = (timestamp) => new Date(timestamp).getSeconds();
437
+ var GET_MILLISECOND = (timestamp) => new Date(timestamp).getMilliseconds();
438
+ var GET_WEEKDAY = (timestamp) => new Date(timestamp).getDay();
439
+ var GET_DAY_OF_YEAR = (timestamp) => {
440
+ const date = new Date(timestamp);
441
+ const start = new Date(date.getFullYear(), 0, 0);
442
+ const diff = date.getTime() - start.getTime();
443
+ const oneDay = 1000 * 60 * 60 * 24;
444
+ return Math.floor(diff / oneDay);
445
+ };
446
+ var GET_QUARTER = (timestamp) => {
447
+ const month = new Date(timestamp).getMonth();
448
+ return Math.floor(month / 3) + 1;
449
+ };
450
+ var DIFFERENCE_IN_SECONDS = (ts1, ts2) => Math.abs(ts1 - ts2) / 1000;
451
+ var DIFFERENCE_IN_MINUTES = (ts1, ts2) => Math.abs(ts1 - ts2) / (60 * 1000);
452
+ var DIFFERENCE_IN_HOURS = (ts1, ts2) => Math.abs(ts1 - ts2) / (60 * 60 * 1000);
453
+ var DIFFERENCE_IN_DAYS = (ts1, ts2) => Math.abs(ts1 - ts2) / (24 * 60 * 60 * 1000);
454
+ var DIFFERENCE_IN_WEEKS = (ts1, ts2) => Math.abs(ts1 - ts2) / (7 * 24 * 60 * 60 * 1000);
455
+ var START_OF_DAY = (timestamp) => {
456
+ const date = new Date(timestamp);
457
+ date.setHours(0, 0, 0, 0);
458
+ return date.getTime();
459
+ };
460
+ var END_OF_DAY = (timestamp) => {
461
+ const date = new Date(timestamp);
462
+ date.setHours(23, 59, 59, 999);
463
+ return date.getTime();
464
+ };
465
+ var START_OF_WEEK = (timestamp) => {
466
+ const date = new Date(timestamp);
467
+ const day = date.getDay();
468
+ const diff = date.getDate() - day;
469
+ date.setDate(diff);
470
+ date.setHours(0, 0, 0, 0);
471
+ return date.getTime();
472
+ };
473
+ var START_OF_MONTH = (timestamp) => {
474
+ const date = new Date(timestamp);
475
+ date.setDate(1);
476
+ date.setHours(0, 0, 0, 0);
477
+ return date.getTime();
478
+ };
479
+ var END_OF_MONTH = (timestamp) => {
480
+ const date = new Date(timestamp);
481
+ date.setMonth(date.getMonth() + 1, 0);
482
+ date.setHours(23, 59, 59, 999);
483
+ return date.getTime();
484
+ };
485
+ var START_OF_YEAR = (timestamp) => {
486
+ const date = new Date(timestamp);
487
+ date.setMonth(0, 1);
488
+ date.setHours(0, 0, 0, 0);
489
+ return date.getTime();
490
+ };
491
+ var END_OF_YEAR = (timestamp) => {
492
+ const date = new Date(timestamp);
493
+ date.setMonth(11, 31);
494
+ date.setHours(23, 59, 59, 999);
495
+ return date.getTime();
496
+ };
497
+ var ADD_DAYS = (timestamp, days) => {
498
+ const date = new Date(timestamp);
499
+ date.setDate(date.getDate() + days);
500
+ return date.getTime();
501
+ };
502
+ var ADD_MONTHS = (timestamp, months) => {
503
+ const date = new Date(timestamp);
504
+ date.setMonth(date.getMonth() + months);
505
+ return date.getTime();
506
+ };
507
+ var ADD_YEARS = (timestamp, years) => {
508
+ const date = new Date(timestamp);
509
+ date.setFullYear(date.getFullYear() + years);
510
+ return date.getTime();
511
+ };
512
+ var IS_BEFORE = (ts1, ts2) => {
513
+ return ts1 < ts2 ? 1 : 0;
514
+ };
515
+ var IS_AFTER = (ts1, ts2) => {
516
+ return ts1 > ts2 ? 1 : 0;
517
+ };
518
+ var IS_SAME_DAY = (ts1, ts2) => {
519
+ const date1 = new Date(ts1);
520
+ const date2 = new Date(ts2);
521
+ return date1.getFullYear() === date2.getFullYear() && date1.getMonth() === date2.getMonth() && date1.getDate() === date2.getDate() ? 1 : 0;
522
+ };
523
+ var IS_WEEKEND = (timestamp) => {
524
+ const day = new Date(timestamp).getDay();
525
+ return day === 0 || day === 6 ? 1 : 0;
526
+ };
527
+ var IS_LEAP_YEAR = (timestamp) => {
528
+ const year = new Date(timestamp).getFullYear();
529
+ return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0 ? 1 : 0;
530
+ };
531
+ var START_OF_QUARTER = (timestamp) => {
532
+ const date = new Date(timestamp);
533
+ const quarter = Math.floor(date.getMonth() / 3);
534
+ date.setMonth(quarter * 3, 1);
535
+ date.setHours(0, 0, 0, 0);
536
+ return date.getTime();
537
+ };
538
+ var TO_UNIX_SECONDS = (timestamp) => Math.floor(timestamp / 1000);
539
+ var FROM_UNIX_SECONDS = (seconds) => seconds * 1000;
376
540
  // src/defaults.ts
377
541
  var defaultContext = {
378
542
  functions: {
379
- abs: Math.abs,
380
- ceil: Math.ceil,
381
- floor: Math.floor,
382
- round: Math.round,
383
- sqrt: Math.sqrt,
384
- min: Math.min,
385
- max: Math.max,
386
- sin: Math.sin,
387
- cos: Math.cos,
388
- tan: Math.tan,
389
- log: Math.log,
390
- log10: Math.log10,
391
- exp: Math.exp,
392
- now: () => Date.now(),
393
- timestamp: (year, month, day, hour = 0, minute = 0, second = 0) => new Date(year, month - 1, day, hour, minute, second).getTime(),
394
- milliseconds: (ms) => ms,
395
- seconds: (s) => s * 1000,
396
- minutes: (m) => m * 60 * 1000,
397
- hours: (h) => h * 60 * 60 * 1000,
398
- days: (d) => d * 24 * 60 * 60 * 1000,
399
- weeks: (w) => w * 7 * 24 * 60 * 60 * 1000,
400
- year: (timestamp) => new Date(timestamp).getFullYear(),
401
- month: (timestamp) => new Date(timestamp).getMonth() + 1,
402
- day: (timestamp) => new Date(timestamp).getDate(),
403
- hour: (timestamp) => new Date(timestamp).getHours(),
404
- minute: (timestamp) => new Date(timestamp).getMinutes(),
405
- second: (timestamp) => new Date(timestamp).getSeconds(),
406
- weekday: (timestamp) => new Date(timestamp).getDay()
543
+ ABS: Math.abs,
544
+ CEIL: Math.ceil,
545
+ FLOOR: Math.floor,
546
+ ROUND: Math.round,
547
+ SQRT: Math.sqrt,
548
+ MIN: Math.min,
549
+ MAX: Math.max,
550
+ SIN: Math.sin,
551
+ COS: Math.cos,
552
+ TAN: Math.tan,
553
+ LOG: Math.log,
554
+ LOG10: Math.log10,
555
+ EXP: Math.exp,
556
+ ...exports_date_utils
407
557
  }
408
558
  };
409
559
  // src/lexer.ts
@@ -910,6 +1060,7 @@ export {
910
1060
  generate,
911
1061
  execute,
912
1062
  defaultContext,
1063
+ exports_date_utils as dateUtils,
913
1064
  exports_ast as ast,
914
1065
  TokenType,
915
1066
  Parser,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "littlewing",
3
- "version": "0.6.0",
3
+ "version": "0.7.0",
4
4
  "description": "A minimal, high-performance arithmetic expression language with lexer, parser, and executor. Optimized for browsers with zero dependencies and type-safe execution.",
5
5
  "keywords": [
6
6
  "arithmetic",