littlewing 0.7.0 → 0.8.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/README.md CHANGED
@@ -209,23 +209,21 @@ interface ExecutionContext {
209
209
 
210
210
  The `defaultContext` includes these built-in functions:
211
211
 
212
- **Math:** `ABS`, `CEIL`, `FLOOR`, `ROUND`, `SQRT`, `MIN`, `MAX`, `SIN`, `COS`, `TAN`, `LOG`, `LOG10`, `EXP`
212
+ **Math:** `ABS`, `CEIL`, `FLOOR`, `ROUND`, `SQRT`, `MIN`, `MAX`, `CLAMP`, `SIN`, `COS`, `TAN`, `LOG`, `LOG10`, `EXP`
213
213
 
214
214
  **Timestamps:** `NOW`, `DATE`
215
215
 
216
- **Time converters (to milliseconds):** `FROM_SECONDS`, `FROM_MINUTES`, `FROM_HOURS`, `FROM_DAYS`, `FROM_WEEKS`, `FROM_MONTHS`, `FROM_YEARS`
216
+ **Time converters (to milliseconds):** `FROM_DAYS`, `FROM_WEEKS`, `FROM_MONTHS`, `FROM_YEARS`
217
217
 
218
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
219
 
220
- **Time differences (always positive):** `DIFFERENCE_IN_SECONDS`, `DIFFERENCE_IN_MINUTES`, `DIFFERENCE_IN_HOURS`, `DIFFERENCE_IN_DAYS`, `DIFFERENCE_IN_WEEKS`
220
+ **Time differences (always positive):** `DIFFERENCE_IN_SECONDS`, `DIFFERENCE_IN_MINUTES`, `DIFFERENCE_IN_HOURS`, `DIFFERENCE_IN_DAYS`, `DIFFERENCE_IN_WEEKS`, `DIFFERENCE_IN_MONTHS`, `DIFFERENCE_IN_YEARS`
221
221
 
222
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
223
 
224
224
  **Date arithmetic:** `ADD_DAYS`, `ADD_MONTHS`, `ADD_YEARS`
225
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`
226
+ **Date comparisons:** `IS_SAME_DAY`, `IS_WEEKEND`, `IS_LEAP_YEAR` (use `<`, `>`, `<=`, `>=` operators for before/after comparisons)
229
227
 
230
228
  ## Use Cases
231
229
 
package/dist/index.d.ts CHANGED
@@ -1,6 +1,3 @@
1
- declare namespace exports_ast {
2
- export { unaryOp, subtract, program, number, notEquals, negate, multiply, modulo, logicalOr, logicalAnd, lessThan, lessEqual, identifier, greaterThan, greaterEqual, functionCall, exponentiate, equals, divide, conditional, binaryOp, assign, add };
3
- }
4
1
  /**
5
2
  * Runtime value type - only numbers
6
3
  */
@@ -134,6 +131,31 @@ declare function isAssignment(node: ASTNode): node is Assignment;
134
131
  declare function isProgram(node: ASTNode): node is Program;
135
132
  declare function isConditionalExpression(node: ASTNode): node is ConditionalExpression;
136
133
  /**
134
+ * Extracts input variables from an AST.
135
+ *
136
+ * Input variables are those whose values can be determined without knowing
137
+ * the values of other variables in the script. This includes:
138
+ * - Literals (10, -5, 3.14)
139
+ * - Unary minus of literals (-10)
140
+ * - Constant expressions (2 + 3, -5 * 2)
141
+ * - Function calls with constant arguments (MAX(10, 20), NOW())
142
+ *
143
+ * Computed variables (those that reference other variables) are excluded.
144
+ *
145
+ * @param ast - The AST to analyze (can be a single statement or Program node)
146
+ * @returns Array of input variable names
147
+ *
148
+ * @example
149
+ * ```typescript
150
+ * const ast = parseSource('price = 100; tax = price * 0.08')
151
+ * extractInputVariables(ast) // ['price']
152
+ * ```
153
+ */
154
+ declare function extractInputVariables(ast: ASTNode): string[];
155
+ declare namespace exports_ast {
156
+ export { unaryOp, subtract, program, number, notEquals, negate, multiply, modulo, logicalOr, logicalAnd, lessThan, lessEqual, identifier, greaterThan, greaterEqual, functionCall, exponentiate, equals, divide, conditional, binaryOp, assign, add };
157
+ }
158
+ /**
137
159
  * Builder functions for creating AST nodes manually
138
160
  */
139
161
  /**
@@ -295,35 +317,28 @@ declare class CodeGenerator {
295
317
  */
296
318
  declare function generate(node: ASTNode): string;
297
319
  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 };
320
+ export { START_OF_YEAR, START_OF_WEEK, START_OF_QUARTER, START_OF_MONTH, START_OF_DAY, NOW, IS_WEEKEND, IS_SAME_DAY, IS_LEAP_YEAR, 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_MONTHS, FROM_DAYS, END_OF_YEAR, END_OF_MONTH, END_OF_DAY, DIFFERENCE_IN_YEARS, DIFFERENCE_IN_WEEKS, DIFFERENCE_IN_SECONDS, DIFFERENCE_IN_MONTHS, DIFFERENCE_IN_MINUTES, DIFFERENCE_IN_HOURS, DIFFERENCE_IN_DAYS, DATE, ADD_YEARS, ADD_MONTHS, ADD_DAYS };
299
321
  }
300
322
  /**
301
323
  * Date utility functions for working with timestamps
302
324
  * All functions work with milliseconds since Unix epoch (numbers only)
325
+ *
326
+ * IMPORTANT: All functions use UTC timezone for consistency and predictability
327
+ * across different server environments. This ensures the same inputs always
328
+ * produce the same outputs regardless of the machine's local timezone.
303
329
  */
304
330
  /**
305
331
  * Get current timestamp (milliseconds since Unix epoch)
306
332
  */
307
333
  declare const NOW: () => number;
308
334
  /**
309
- * Create timestamp from date components
335
+ * Create timestamp from date components (UTC timezone)
310
336
  * Year is required, all other parameters default to minimum values
311
337
  * Month is 1-based (1 = January, 12 = December)
338
+ * All parameters are interpreted in UTC timezone for consistency
312
339
  */
313
340
  declare const DATE: (year: number, month?: number, day?: number, hour?: number, minute?: number, second?: number) => number;
314
341
  /**
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
342
  * Convert days to milliseconds
328
343
  */
329
344
  declare const FROM_DAYS: (d: number) => number;
@@ -333,150 +348,159 @@ declare const FROM_DAYS: (d: number) => number;
333
348
  declare const FROM_WEEKS: (w: number) => number;
334
349
  /**
335
350
  * Convert months to milliseconds (approximate: 30 days per month)
351
+ * WARNING: This is an approximation. Not all months have 30 days.
352
+ * For accurate month arithmetic, use ADD_MONTHS() instead.
336
353
  */
337
354
  declare const FROM_MONTHS: (months: number) => number;
338
355
  /**
339
356
  * Convert years to milliseconds (approximate: 365 days per year)
357
+ * WARNING: This is an approximation. Leap years have 366 days.
358
+ * For accurate year arithmetic, use ADD_YEARS() instead.
340
359
  */
341
360
  declare const FROM_YEARS: (years: number) => number;
342
361
  /**
343
- * Get the year from a timestamp
362
+ * Get the year from a timestamp (UTC)
344
363
  */
345
364
  declare const GET_YEAR: (timestamp: number) => number;
346
365
  /**
347
- * Get the month from a timestamp (1-based: 1 = January, 12 = December)
366
+ * Get the month from a timestamp (1-based: 1 = January, 12 = December, UTC)
348
367
  */
349
368
  declare const GET_MONTH: (timestamp: number) => number;
350
369
  /**
351
- * Get the day of month from a timestamp (1-31)
370
+ * Get the day of month from a timestamp (1-31, UTC)
352
371
  */
353
372
  declare const GET_DAY: (timestamp: number) => number;
354
373
  /**
355
- * Get the hour from a timestamp (0-23)
374
+ * Get the hour from a timestamp (0-23, UTC)
356
375
  */
357
376
  declare const GET_HOUR: (timestamp: number) => number;
358
377
  /**
359
- * Get the minute from a timestamp (0-59)
378
+ * Get the minute from a timestamp (0-59, UTC)
360
379
  */
361
380
  declare const GET_MINUTE: (timestamp: number) => number;
362
381
  /**
363
- * Get the second from a timestamp (0-59)
382
+ * Get the second from a timestamp (0-59, UTC)
364
383
  */
365
384
  declare const GET_SECOND: (timestamp: number) => number;
366
385
  /**
367
- * Get the millisecond component from a timestamp (0-999)
386
+ * Get the millisecond component from a timestamp (0-999, UTC)
368
387
  */
369
388
  declare const GET_MILLISECOND: (timestamp: number) => number;
370
389
  /**
371
- * Get the day of week from a timestamp (0 = Sunday, 6 = Saturday)
390
+ * Get the day of week from a timestamp (0 = Sunday, 6 = Saturday, UTC)
372
391
  */
373
392
  declare const GET_WEEKDAY: (timestamp: number) => number;
374
393
  /**
375
- * Get the day of year (1-366) from a timestamp
394
+ * Get the day of year (1-366) from a timestamp (UTC)
395
+ * January 1st = 1, December 31st = 365 or 366 (leap year)
376
396
  */
377
397
  declare const GET_DAY_OF_YEAR: (timestamp: number) => number;
378
398
  /**
379
- * Get the quarter (1-4) from a timestamp
399
+ * Get the quarter (1-4) from a timestamp (UTC)
380
400
  */
381
401
  declare const GET_QUARTER: (timestamp: number) => number;
382
402
  /**
383
- * Get the absolute difference between two timestamps in seconds
403
+ * Get the absolute difference between two timestamps in seconds (whole seconds)
384
404
  */
385
405
  declare const DIFFERENCE_IN_SECONDS: (ts1: number, ts2: number) => number;
386
406
  /**
387
- * Get the absolute difference between two timestamps in minutes
407
+ * Get the absolute difference between two timestamps in minutes (whole minutes)
388
408
  */
389
409
  declare const DIFFERENCE_IN_MINUTES: (ts1: number, ts2: number) => number;
390
410
  /**
391
- * Get the absolute difference between two timestamps in hours
411
+ * Get the absolute difference between two timestamps in hours (whole hours)
392
412
  */
393
413
  declare const DIFFERENCE_IN_HOURS: (ts1: number, ts2: number) => number;
394
414
  /**
395
- * Get the absolute difference between two timestamps in days
415
+ * Get the absolute difference between two timestamps in days (whole days)
396
416
  */
397
417
  declare const DIFFERENCE_IN_DAYS: (ts1: number, ts2: number) => number;
398
418
  /**
399
- * Get the absolute difference between two timestamps in weeks
419
+ * Get the absolute difference between two timestamps in weeks (whole weeks)
400
420
  */
401
421
  declare const DIFFERENCE_IN_WEEKS: (ts1: number, ts2: number) => number;
402
422
  /**
403
- * Get the start of day (00:00:00.000) for a given timestamp
423
+ * Get the number of full calendar months between two timestamps (UTC)
424
+ * Counts complete months where the same day-of-month has been reached
425
+ *
426
+ * Examples:
427
+ * Jan 15 → Feb 14 = 0 months (Feb 15 not reached yet)
428
+ * Jan 15 → Feb 15 = 1 month
429
+ * Jan 31 → Feb 28 = 0 months (Feb 31 doesn't exist)
430
+ * Jan 31 → Mar 31 = 2 months
431
+ */
432
+ declare const DIFFERENCE_IN_MONTHS: (ts1: number, ts2: number) => number;
433
+ /**
434
+ * Get the number of full calendar years between two timestamps (UTC)
435
+ * Counts complete years where the same month and day have been reached
436
+ *
437
+ * Examples:
438
+ * Jan 15, 2020 → Jan 14, 2021 = 0 years (Jan 15 not reached)
439
+ * Jan 15, 2020 → Jan 15, 2021 = 1 year
440
+ * Feb 29, 2020 → Feb 28, 2021 = 0 years (Feb 29 doesn't exist)
441
+ * Feb 29, 2020 → Mar 1, 2021 = 1 year
442
+ */
443
+ declare const DIFFERENCE_IN_YEARS: (ts1: number, ts2: number) => number;
444
+ /**
445
+ * Get the start of day (00:00:00.000 UTC) for a given timestamp
404
446
  */
405
447
  declare const START_OF_DAY: (timestamp: number) => number;
406
448
  /**
407
- * Get the end of day (23:59:59.999) for a given timestamp
449
+ * Get the end of day (23:59:59.999 UTC) for a given timestamp
408
450
  */
409
451
  declare const END_OF_DAY: (timestamp: number) => number;
410
452
  /**
411
- * Get the start of week (Sunday at 00:00:00.000) for a given timestamp
453
+ * Get the start of week (Sunday at 00:00:00.000 UTC) for a given timestamp
412
454
  */
413
455
  declare const START_OF_WEEK: (timestamp: number) => number;
414
456
  /**
415
- * Get the start of month (1st day at 00:00:00.000) for a given timestamp
457
+ * Get the start of month (1st day at 00:00:00.000 UTC) for a given timestamp
416
458
  */
417
459
  declare const START_OF_MONTH: (timestamp: number) => number;
418
460
  /**
419
- * Get the end of month (last day at 23:59:59.999) for a given timestamp
461
+ * Get the end of month (last day at 23:59:59.999 UTC) for a given timestamp
420
462
  */
421
463
  declare const END_OF_MONTH: (timestamp: number) => number;
422
464
  /**
423
- * Get the start of year (Jan 1st at 00:00:00.000) for a given timestamp
465
+ * Get the start of year (Jan 1st at 00:00:00.000 UTC) for a given timestamp
424
466
  */
425
467
  declare const START_OF_YEAR: (timestamp: number) => number;
426
468
  /**
427
- * Get the end of year (Dec 31st at 23:59:59.999) for a given timestamp
469
+ * Get the end of year (Dec 31st at 23:59:59.999 UTC) for a given timestamp
428
470
  */
429
471
  declare const END_OF_YEAR: (timestamp: number) => number;
430
472
  /**
431
- * Add days to a timestamp
473
+ * Add days to a timestamp (UTC)
432
474
  */
433
475
  declare const ADD_DAYS: (timestamp: number, days: number) => number;
434
476
  /**
435
- * Add months to a timestamp (handles variable month lengths correctly)
477
+ * Add months to a timestamp (handles variable month lengths correctly, UTC)
436
478
  */
437
479
  declare const ADD_MONTHS: (timestamp: number, months: number) => number;
438
480
  /**
439
- * Add years to a timestamp
481
+ * Add years to a timestamp (UTC)
440
482
  */
441
483
  declare const ADD_YEARS: (timestamp: number, years: number) => number;
442
484
  /**
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
485
+ * Check if two timestamps are on the same calendar day (UTC)
454
486
  * Returns 1 if true, 0 if false
455
487
  */
456
488
  declare const IS_SAME_DAY: (ts1: number, ts2: number) => number;
457
489
  /**
458
- * Check if timestamp falls on a weekend (Saturday or Sunday)
490
+ * Check if timestamp falls on a weekend (Saturday or Sunday, UTC)
459
491
  * Returns 1 if true, 0 if false
460
492
  */
461
493
  declare const IS_WEEKEND: (timestamp: number) => number;
462
494
  /**
463
- * Check if timestamp is in a leap year
495
+ * Check if timestamp is in a leap year (UTC)
464
496
  * Returns 1 if true, 0 if false
465
497
  */
466
498
  declare const IS_LEAP_YEAR: (timestamp: number) => number;
467
499
  /**
468
- * Get the start of quarter for a given timestamp
500
+ * Get the start of quarter for a given timestamp (UTC)
469
501
  */
470
502
  declare const START_OF_QUARTER: (timestamp: number) => number;
471
503
  /**
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
504
  * Default execution context with common Math functions and date/time utilities
481
505
  * Users can use this as-is or spread it into their own context
482
506
  *
@@ -682,4 +706,4 @@ declare class Parser {
682
706
  * @returns Parsed AST
683
707
  */
684
708
  declare function parseSource(source: string): 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 };
709
+ export { parseSource, optimize, isUnaryOp, isProgram, isNumberLiteral, isIdentifier, isFunctionCall, isConditionalExpression, isBinaryOp, isAssignment, generate, extractInputVariables, 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
@@ -10,6 +10,92 @@ var __export = (target, all) => {
10
10
  });
11
11
  };
12
12
 
13
+ // src/types.ts
14
+ var TokenType;
15
+ ((TokenType2) => {
16
+ TokenType2["NUMBER"] = "NUMBER";
17
+ TokenType2["IDENTIFIER"] = "IDENTIFIER";
18
+ TokenType2["PLUS"] = "PLUS";
19
+ TokenType2["MINUS"] = "MINUS";
20
+ TokenType2["STAR"] = "STAR";
21
+ TokenType2["SLASH"] = "SLASH";
22
+ TokenType2["PERCENT"] = "PERCENT";
23
+ TokenType2["CARET"] = "CARET";
24
+ TokenType2["DOUBLE_EQUALS"] = "DOUBLE_EQUALS";
25
+ TokenType2["NOT_EQUALS"] = "NOT_EQUALS";
26
+ TokenType2["LESS_THAN"] = "LESS_THAN";
27
+ TokenType2["GREATER_THAN"] = "GREATER_THAN";
28
+ TokenType2["LESS_EQUAL"] = "LESS_EQUAL";
29
+ TokenType2["GREATER_EQUAL"] = "GREATER_EQUAL";
30
+ TokenType2["LOGICAL_AND"] = "LOGICAL_AND";
31
+ TokenType2["LOGICAL_OR"] = "LOGICAL_OR";
32
+ TokenType2["LPAREN"] = "LPAREN";
33
+ TokenType2["RPAREN"] = "RPAREN";
34
+ TokenType2["EQUALS"] = "EQUALS";
35
+ TokenType2["COMMA"] = "COMMA";
36
+ TokenType2["QUESTION"] = "QUESTION";
37
+ TokenType2["COLON"] = "COLON";
38
+ TokenType2["EOF"] = "EOF";
39
+ })(TokenType ||= {});
40
+ function isNumberLiteral(node) {
41
+ return node.type === "NumberLiteral";
42
+ }
43
+ function isIdentifier(node) {
44
+ return node.type === "Identifier";
45
+ }
46
+ function isBinaryOp(node) {
47
+ return node.type === "BinaryOp";
48
+ }
49
+ function isUnaryOp(node) {
50
+ return node.type === "UnaryOp";
51
+ }
52
+ function isFunctionCall(node) {
53
+ return node.type === "FunctionCall";
54
+ }
55
+ function isAssignment(node) {
56
+ return node.type === "Assignment";
57
+ }
58
+ function isProgram(node) {
59
+ return node.type === "Program";
60
+ }
61
+ function isConditionalExpression(node) {
62
+ return node.type === "ConditionalExpression";
63
+ }
64
+
65
+ // src/analyzer.ts
66
+ function extractInputVariables(ast) {
67
+ const inputVars = new Set;
68
+ const statements = isProgram(ast) ? ast.statements : [ast];
69
+ for (const statement of statements) {
70
+ if (isAssignment(statement)) {
71
+ if (!containsVariableReference(statement.value)) {
72
+ inputVars.add(statement.name);
73
+ }
74
+ }
75
+ }
76
+ return Array.from(inputVars);
77
+ }
78
+ function containsVariableReference(node) {
79
+ if (isIdentifier(node)) {
80
+ return true;
81
+ }
82
+ if (isNumberLiteral(node)) {
83
+ return false;
84
+ }
85
+ if (isBinaryOp(node)) {
86
+ return containsVariableReference(node.left) || containsVariableReference(node.right);
87
+ }
88
+ if (isUnaryOp(node)) {
89
+ return containsVariableReference(node.argument);
90
+ }
91
+ if (isFunctionCall(node)) {
92
+ return node.arguments.some((arg) => containsVariableReference(arg));
93
+ }
94
+ if (isConditionalExpression(node)) {
95
+ return containsVariableReference(node.condition) || containsVariableReference(node.consequent) || containsVariableReference(node.alternate);
96
+ }
97
+ return false;
98
+ }
13
99
  // src/ast.ts
14
100
  var exports_ast = {};
15
101
  __export(exports_ast, {
@@ -137,58 +223,6 @@ function logicalAnd(left, right) {
137
223
  function logicalOr(left, right) {
138
224
  return binaryOp(left, "||", right);
139
225
  }
140
- // src/types.ts
141
- var TokenType;
142
- ((TokenType2) => {
143
- TokenType2["NUMBER"] = "NUMBER";
144
- TokenType2["IDENTIFIER"] = "IDENTIFIER";
145
- TokenType2["PLUS"] = "PLUS";
146
- TokenType2["MINUS"] = "MINUS";
147
- TokenType2["STAR"] = "STAR";
148
- TokenType2["SLASH"] = "SLASH";
149
- TokenType2["PERCENT"] = "PERCENT";
150
- TokenType2["CARET"] = "CARET";
151
- TokenType2["DOUBLE_EQUALS"] = "DOUBLE_EQUALS";
152
- TokenType2["NOT_EQUALS"] = "NOT_EQUALS";
153
- TokenType2["LESS_THAN"] = "LESS_THAN";
154
- TokenType2["GREATER_THAN"] = "GREATER_THAN";
155
- TokenType2["LESS_EQUAL"] = "LESS_EQUAL";
156
- TokenType2["GREATER_EQUAL"] = "GREATER_EQUAL";
157
- TokenType2["LOGICAL_AND"] = "LOGICAL_AND";
158
- TokenType2["LOGICAL_OR"] = "LOGICAL_OR";
159
- TokenType2["LPAREN"] = "LPAREN";
160
- TokenType2["RPAREN"] = "RPAREN";
161
- TokenType2["EQUALS"] = "EQUALS";
162
- TokenType2["COMMA"] = "COMMA";
163
- TokenType2["QUESTION"] = "QUESTION";
164
- TokenType2["COLON"] = "COLON";
165
- TokenType2["EOF"] = "EOF";
166
- })(TokenType ||= {});
167
- function isNumberLiteral(node) {
168
- return node.type === "NumberLiteral";
169
- }
170
- function isIdentifier(node) {
171
- return node.type === "Identifier";
172
- }
173
- function isBinaryOp(node) {
174
- return node.type === "BinaryOp";
175
- }
176
- function isUnaryOp(node) {
177
- return node.type === "UnaryOp";
178
- }
179
- function isFunctionCall(node) {
180
- return node.type === "FunctionCall";
181
- }
182
- function isAssignment(node) {
183
- return node.type === "Assignment";
184
- }
185
- function isProgram(node) {
186
- return node.type === "Program";
187
- }
188
- function isConditionalExpression(node) {
189
- return node.type === "ConditionalExpression";
190
- }
191
-
192
226
  // src/utils.ts
193
227
  function evaluateBinaryOperation(operator, left, right) {
194
228
  switch (operator) {
@@ -376,7 +410,6 @@ function generate(node) {
376
410
  // src/date-utils.ts
377
411
  var exports_date_utils = {};
378
412
  __export(exports_date_utils, {
379
- TO_UNIX_SECONDS: () => TO_UNIX_SECONDS,
380
413
  START_OF_YEAR: () => START_OF_YEAR,
381
414
  START_OF_WEEK: () => START_OF_WEEK,
382
415
  START_OF_QUARTER: () => START_OF_QUARTER,
@@ -386,8 +419,6 @@ __export(exports_date_utils, {
386
419
  IS_WEEKEND: () => IS_WEEKEND,
387
420
  IS_SAME_DAY: () => IS_SAME_DAY,
388
421
  IS_LEAP_YEAR: () => IS_LEAP_YEAR,
389
- IS_BEFORE: () => IS_BEFORE,
390
- IS_AFTER: () => IS_AFTER,
391
422
  GET_YEAR: () => GET_YEAR,
392
423
  GET_WEEKDAY: () => GET_WEEKDAY,
393
424
  GET_SECOND: () => GET_SECOND,
@@ -400,17 +431,15 @@ __export(exports_date_utils, {
400
431
  GET_DAY: () => GET_DAY,
401
432
  FROM_YEARS: () => FROM_YEARS,
402
433
  FROM_WEEKS: () => FROM_WEEKS,
403
- FROM_UNIX_SECONDS: () => FROM_UNIX_SECONDS,
404
- FROM_SECONDS: () => FROM_SECONDS,
405
434
  FROM_MONTHS: () => FROM_MONTHS,
406
- FROM_MINUTES: () => FROM_MINUTES,
407
- FROM_HOURS: () => FROM_HOURS,
408
435
  FROM_DAYS: () => FROM_DAYS,
409
436
  END_OF_YEAR: () => END_OF_YEAR,
410
437
  END_OF_MONTH: () => END_OF_MONTH,
411
438
  END_OF_DAY: () => END_OF_DAY,
439
+ DIFFERENCE_IN_YEARS: () => DIFFERENCE_IN_YEARS,
412
440
  DIFFERENCE_IN_WEEKS: () => DIFFERENCE_IN_WEEKS,
413
441
  DIFFERENCE_IN_SECONDS: () => DIFFERENCE_IN_SECONDS,
442
+ DIFFERENCE_IN_MONTHS: () => DIFFERENCE_IN_MONTHS,
414
443
  DIFFERENCE_IN_MINUTES: () => DIFFERENCE_IN_MINUTES,
415
444
  DIFFERENCE_IN_HOURS: () => DIFFERENCE_IN_HOURS,
416
445
  DIFFERENCE_IN_DAYS: () => DIFFERENCE_IN_DAYS,
@@ -420,123 +449,114 @@ __export(exports_date_utils, {
420
449
  ADD_DAYS: () => ADD_DAYS
421
450
  });
422
451
  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;
452
+ var DATE = (year, month = 1, day = 1, hour = 0, minute = 0, second = 0) => Date.UTC(year, month - 1, day, hour, minute, second);
427
453
  var FROM_DAYS = (d) => d * 24 * 60 * 60 * 1000;
428
454
  var FROM_WEEKS = (w) => w * 7 * 24 * 60 * 60 * 1000;
429
455
  var FROM_MONTHS = (months) => months * 30 * 24 * 60 * 60 * 1000;
430
456
  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();
457
+ var GET_YEAR = (timestamp) => new Date(timestamp).getUTCFullYear();
458
+ var GET_MONTH = (timestamp) => new Date(timestamp).getUTCMonth() + 1;
459
+ var GET_DAY = (timestamp) => new Date(timestamp).getUTCDate();
460
+ var GET_HOUR = (timestamp) => new Date(timestamp).getUTCHours();
461
+ var GET_MINUTE = (timestamp) => new Date(timestamp).getUTCMinutes();
462
+ var GET_SECOND = (timestamp) => new Date(timestamp).getUTCSeconds();
463
+ var GET_MILLISECOND = (timestamp) => new Date(timestamp).getUTCMilliseconds();
464
+ var GET_WEEKDAY = (timestamp) => new Date(timestamp).getUTCDay();
439
465
  var GET_DAY_OF_YEAR = (timestamp) => {
440
466
  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);
467
+ const year = date.getUTCFullYear();
468
+ const startOfYear = Date.UTC(year, 0, 1);
469
+ const diff = timestamp - startOfYear;
470
+ const oneDay = 86400000;
471
+ return Math.floor(diff / oneDay) + 1;
445
472
  };
446
473
  var GET_QUARTER = (timestamp) => {
447
- const month = new Date(timestamp).getMonth();
474
+ const month = new Date(timestamp).getUTCMonth();
448
475
  return Math.floor(month / 3) + 1;
449
476
  };
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);
477
+ var DIFFERENCE_IN_SECONDS = (ts1, ts2) => Math.floor(Math.abs(ts1 - ts2) / 1000);
478
+ var DIFFERENCE_IN_MINUTES = (ts1, ts2) => Math.floor(Math.abs(ts1 - ts2) / (60 * 1000));
479
+ var DIFFERENCE_IN_HOURS = (ts1, ts2) => Math.floor(Math.abs(ts1 - ts2) / (60 * 60 * 1000));
480
+ var DIFFERENCE_IN_DAYS = (ts1, ts2) => Math.floor(Math.abs(ts1 - ts2) / (24 * 60 * 60 * 1000));
481
+ var DIFFERENCE_IN_WEEKS = (ts1, ts2) => Math.floor(Math.abs(ts1 - ts2) / (7 * 24 * 60 * 60 * 1000));
482
+ var DIFFERENCE_IN_MONTHS = (ts1, ts2) => {
483
+ const smaller = Math.min(ts1, ts2);
484
+ const larger = Math.max(ts1, ts2);
485
+ const date1 = new Date(smaller);
486
+ const date2 = new Date(larger);
487
+ const yearDiff = date2.getUTCFullYear() - date1.getUTCFullYear();
488
+ const monthDiff = date2.getUTCMonth() - date1.getUTCMonth();
489
+ let months = yearDiff * 12 + monthDiff;
490
+ if (date2.getUTCDate() < date1.getUTCDate()) {
491
+ months--;
492
+ }
493
+ return months;
494
+ };
495
+ var DIFFERENCE_IN_YEARS = (ts1, ts2) => {
496
+ return Math.floor(DIFFERENCE_IN_MONTHS(ts1, ts2) / 12);
497
+ };
455
498
  var START_OF_DAY = (timestamp) => {
456
499
  const date = new Date(timestamp);
457
- date.setHours(0, 0, 0, 0);
458
- return date.getTime();
500
+ return Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), 0, 0, 0, 0);
459
501
  };
460
502
  var END_OF_DAY = (timestamp) => {
461
503
  const date = new Date(timestamp);
462
- date.setHours(23, 59, 59, 999);
463
- return date.getTime();
504
+ return Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), 23, 59, 59, 999);
464
505
  };
465
506
  var START_OF_WEEK = (timestamp) => {
466
507
  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();
508
+ const dayOfWeek = date.getUTCDay();
509
+ const currentDay = date.getUTCDate();
510
+ const startDay = currentDay - dayOfWeek;
511
+ return Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), startDay, 0, 0, 0, 0);
472
512
  };
473
513
  var START_OF_MONTH = (timestamp) => {
474
514
  const date = new Date(timestamp);
475
- date.setDate(1);
476
- date.setHours(0, 0, 0, 0);
477
- return date.getTime();
515
+ return Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1, 0, 0, 0, 0);
478
516
  };
479
517
  var END_OF_MONTH = (timestamp) => {
480
518
  const date = new Date(timestamp);
481
- date.setMonth(date.getMonth() + 1, 0);
482
- date.setHours(23, 59, 59, 999);
483
- return date.getTime();
519
+ return Date.UTC(date.getUTCFullYear(), date.getUTCMonth() + 1, 0, 23, 59, 59, 999);
484
520
  };
485
521
  var START_OF_YEAR = (timestamp) => {
486
522
  const date = new Date(timestamp);
487
- date.setMonth(0, 1);
488
- date.setHours(0, 0, 0, 0);
489
- return date.getTime();
523
+ return Date.UTC(date.getUTCFullYear(), 0, 1, 0, 0, 0, 0);
490
524
  };
491
525
  var END_OF_YEAR = (timestamp) => {
492
526
  const date = new Date(timestamp);
493
- date.setMonth(11, 31);
494
- date.setHours(23, 59, 59, 999);
495
- return date.getTime();
527
+ return Date.UTC(date.getUTCFullYear(), 11, 31, 23, 59, 59, 999);
496
528
  };
497
529
  var ADD_DAYS = (timestamp, days) => {
498
530
  const date = new Date(timestamp);
499
- date.setDate(date.getDate() + days);
500
- return date.getTime();
531
+ return Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate() + days, date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds(), date.getUTCMilliseconds());
501
532
  };
502
533
  var ADD_MONTHS = (timestamp, months) => {
503
534
  const date = new Date(timestamp);
504
- date.setMonth(date.getMonth() + months);
505
- return date.getTime();
535
+ return Date.UTC(date.getUTCFullYear(), date.getUTCMonth() + months, date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds(), date.getUTCMilliseconds());
506
536
  };
507
537
  var ADD_YEARS = (timestamp, years) => {
508
538
  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;
539
+ return Date.UTC(date.getUTCFullYear() + years, date.getUTCMonth(), date.getUTCDate(), date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds(), date.getUTCMilliseconds());
517
540
  };
518
541
  var IS_SAME_DAY = (ts1, ts2) => {
519
542
  const date1 = new Date(ts1);
520
543
  const date2 = new Date(ts2);
521
- return date1.getFullYear() === date2.getFullYear() && date1.getMonth() === date2.getMonth() && date1.getDate() === date2.getDate() ? 1 : 0;
544
+ return date1.getUTCFullYear() === date2.getUTCFullYear() && date1.getUTCMonth() === date2.getUTCMonth() && date1.getUTCDate() === date2.getUTCDate() ? 1 : 0;
522
545
  };
523
546
  var IS_WEEKEND = (timestamp) => {
524
- const day = new Date(timestamp).getDay();
547
+ const day = new Date(timestamp).getUTCDay();
525
548
  return day === 0 || day === 6 ? 1 : 0;
526
549
  };
527
550
  var IS_LEAP_YEAR = (timestamp) => {
528
- const year = new Date(timestamp).getFullYear();
551
+ const year = new Date(timestamp).getUTCFullYear();
529
552
  return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0 ? 1 : 0;
530
553
  };
531
554
  var START_OF_QUARTER = (timestamp) => {
532
555
  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();
556
+ const month = date.getUTCMonth();
557
+ const quarterStartMonth = Math.floor(month / 3) * 3;
558
+ return Date.UTC(date.getUTCFullYear(), quarterStartMonth, 1, 0, 0, 0, 0);
537
559
  };
538
- var TO_UNIX_SECONDS = (timestamp) => Math.floor(timestamp / 1000);
539
- var FROM_UNIX_SECONDS = (seconds) => seconds * 1000;
540
560
  // src/defaults.ts
541
561
  var defaultContext = {
542
562
  functions: {
@@ -553,6 +573,9 @@ var defaultContext = {
553
573
  LOG: Math.log,
554
574
  LOG10: Math.log10,
555
575
  EXP: Math.exp,
576
+ CLAMP: (value, min, max) => {
577
+ return value < min ? min : value > max ? max : value;
578
+ },
556
579
  ...exports_date_utils
557
580
  }
558
581
  };
@@ -1058,6 +1081,7 @@ export {
1058
1081
  isBinaryOp,
1059
1082
  isAssignment,
1060
1083
  generate,
1084
+ extractInputVariables,
1061
1085
  execute,
1062
1086
  defaultContext,
1063
1087
  exports_date_utils as dateUtils,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "littlewing",
3
- "version": "0.7.0",
3
+ "version": "0.8.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",