@servicetitan/dte-pdf-editor 1.38.0 → 1.40.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.
Files changed (43) hide show
  1. package/README.md +7 -4
  2. package/dist/components/field-config-panel/advanced-settings.d.ts.map +1 -1
  3. package/dist/components/field-config-panel/advanced-settings.js +1 -6
  4. package/dist/components/field-config-panel/advanced-settings.js.map +1 -1
  5. package/dist/components/field-config-panel/formula-modal.d.ts.map +1 -1
  6. package/dist/components/field-config-panel/formula-modal.js +20 -41
  7. package/dist/components/field-config-panel/formula-modal.js.map +1 -1
  8. package/dist/components/pdf-view/pdf-view-calculated.d.ts.map +1 -1
  9. package/dist/components/pdf-view/pdf-view-calculated.js +2 -16
  10. package/dist/components/pdf-view/pdf-view-calculated.js.map +1 -1
  11. package/dist/constants/calculated.constants.d.ts +1 -0
  12. package/dist/constants/calculated.constants.d.ts.map +1 -1
  13. package/dist/constants/calculated.constants.js +1 -0
  14. package/dist/constants/calculated.constants.js.map +1 -1
  15. package/dist/constants/field.constants.d.ts +7 -1
  16. package/dist/constants/field.constants.d.ts.map +1 -1
  17. package/dist/constants/field.constants.js +20 -0
  18. package/dist/constants/field.constants.js.map +1 -1
  19. package/dist/interface/types.d.ts +11 -5
  20. package/dist/interface/types.d.ts.map +1 -1
  21. package/dist/interface/types.js.map +1 -1
  22. package/dist/utils/formula/evaluate-formula.utils.d.ts +5 -4
  23. package/dist/utils/formula/evaluate-formula.utils.d.ts.map +1 -1
  24. package/dist/utils/formula/evaluate-formula.utils.js +20 -9
  25. package/dist/utils/formula/evaluate-formula.utils.js.map +1 -1
  26. package/dist/utils/formula/expression.utils.d.ts +1 -1
  27. package/dist/utils/formula/expression.utils.d.ts.map +1 -1
  28. package/dist/utils/formula/expression.utils.js +3 -1
  29. package/dist/utils/formula/expression.utils.js.map +1 -1
  30. package/dist/utils/formula/format-calculated-result.utils.d.ts +1 -1
  31. package/dist/utils/formula/format-calculated-result.utils.d.ts.map +1 -1
  32. package/dist/utils/formula/format-calculated-result.utils.js +24 -9
  33. package/dist/utils/formula/format-calculated-result.utils.js.map +1 -1
  34. package/package.json +1 -1
  35. package/src/components/field-config-panel/advanced-settings.tsx +4 -10
  36. package/src/components/field-config-panel/formula-modal.tsx +24 -42
  37. package/src/components/pdf-view/pdf-view-calculated.tsx +2 -15
  38. package/src/constants/calculated.constants.ts +2 -0
  39. package/src/constants/field.constants.ts +28 -0
  40. package/src/interface/types.ts +13 -6
  41. package/src/utils/formula/evaluate-formula.utils.ts +21 -10
  42. package/src/utils/formula/expression.utils.ts +7 -1
  43. package/src/utils/formula/format-calculated-result.utils.ts +30 -14
@@ -14,7 +14,7 @@ export declare function tokenizeExpression(expression: string): ExpressionPart[]
14
14
  * Parse an expression string into FormulaToken[] using valid paths.
15
15
  * Invalid or unknown identifiers are skipped; only known paths become field tokens.
16
16
  */
17
- export declare function parseExpression(expression: string, validPaths: Set<string>): FormulaToken[];
17
+ export declare function parseExpression(expression: string, validPaths: Set<string>, knownDateFields?: Set<string>): FormulaToken[];
18
18
  export interface NormalizeMergeTagsResult {
19
19
  normalized: string;
20
20
  removed: {
@@ -1 +1 @@
1
- {"version":3,"file":"expression.utils.d.ts","sourceRoot":"","sources":["../../../src/utils/formula/expression.utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAExE;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,iBAAiB,GAAG,SAAS,GAAG,MAAM,CAoBjF;AAED,oFAAoF;AACpF,MAAM,WAAW,cAAc;IAC3B,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,GAAG,MAAM,CAAC;IACzD,KAAK,EAAE,MAAM,CAAC;CACjB;AAKD,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,cAAc,EAAE,CAgBvE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,YAAY,EAAE,CAoC3F;AAED,MAAM,WAAW,wBAAwB;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAClD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAC9B,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,GACxB,wBAAwB,CAqC1B"}
1
+ {"version":3,"file":"expression.utils.d.ts","sourceRoot":"","sources":["../../../src/utils/formula/expression.utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAExE;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,iBAAiB,GAAG,SAAS,GAAG,MAAM,CAoBjF;AAED,oFAAoF;AACpF,MAAM,WAAW,cAAc;IAC3B,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,UAAU,GAAG,OAAO,GAAG,MAAM,CAAC;IACzD,KAAK,EAAE,MAAM,CAAC;CACjB;AAKD,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,MAAM,GAAG,cAAc,EAAE,CAgBvE;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC3B,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,EACvB,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GAC9B,YAAY,EAAE,CAsChB;AAED,MAAM,WAAW,wBAAwB;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;CAClD;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAC9B,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,GACxB,wBAAwB,CAqC1B"}
@@ -50,7 +50,7 @@ export function tokenizeExpression(expression) {
50
50
  * Parse an expression string into FormulaToken[] using valid paths.
51
51
  * Invalid or unknown identifiers are skipped; only known paths become field tokens.
52
52
  */
53
- export function parseExpression(expression, validPaths) {
53
+ export function parseExpression(expression, validPaths, knownDateFields) {
54
54
  const parts = tokenizeExpression(expression).filter(p => p.type !== 'text' || p.value.trim() !== '');
55
55
  const tokens = [];
56
56
  for (const part of parts) {
@@ -59,9 +59,11 @@ export function parseExpression(expression, validPaths) {
59
59
  }
60
60
  if (part.type === 'field') {
61
61
  if (validPaths.has(part.value)) {
62
+ const fieldType = (knownDateFields === null || knownDateFields === void 0 ? void 0 : knownDateFields.has(part.value)) ? 'date' : 'number';
62
63
  tokens.push({
63
64
  type: 'field',
64
65
  path: part.value,
66
+ fieldType,
65
67
  });
66
68
  }
67
69
  continue;
@@ -1 +1 @@
1
- {"version":3,"file":"expression.utils.js","sourceRoot":"","sources":["../../../src/utils/formula/expression.utils.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAsC;;IACrE,IAAI,CAAC,CAAA,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,MAAM,0CAAE,MAAM,CAAA,EAAE,CAAC;QAC3B,OAAO,EAAE,CAAC;IACd,CAAC;IACD,OAAO,OAAO,CAAC,MAAM;SAChB,GAAG,CAAC,CAAC,CAAC,EAAE;QACL,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YACrB,OAAO,CAAC,CAAC,IAAI,CAAC;QAClB,CAAC;QACD,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtB,OAAO,GAAG,CAAC;QACf,CAAC;QACD,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtB,OAAO,GAAG,CAAC;QACf,CAAC;QACD,OAAO,CAAC,CAAC,KAAK,CAAC;IACnB,CAAC,CAAC;SACD,IAAI,CAAC,GAAG,CAAC;SACT,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,IAAI,EAAE,CAAC;AAChB,CAAC;AAQD,6EAA6E;AAC7E,MAAM,gBAAgB,GAAG,yDAAyD,CAAC;AAEnF,MAAM,UAAU,kBAAkB,CAAC,UAAkB;IACjD,MAAM,MAAM,GAAqB,EAAE,CAAC;IACpC,IAAI,KAA6B,CAAC;IAClC,OAAO,CAAC,KAAK,GAAG,gBAAgB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC1D,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACvB,IAAI,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3B,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QAC1C,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3B,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;QAC3C,CAAC;aAAM,IAAI,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACnC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,KAAK,GAAG,IAAI,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC;QACxF,CAAC;aAAM,CAAC;YACJ,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QACzC,CAAC;IACL,CAAC;IACD,OAAO,MAAM,CAAC;AAClB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,UAAkB,EAAE,UAAuB;IACvE,MAAM,KAAK,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC,MAAM,CAC/C,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,CAClD,CAAC;IACF,MAAM,MAAM,GAAmB,EAAE,CAAC;IAElC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACvB,SAAS;QACb,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YACxB,IAAI,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC7B,MAAM,CAAC,IAAI,CAAC;oBACR,IAAI,EAAE,OAAO;oBACb,IAAI,EAAE,IAAI,CAAC,KAAK;iBACnB,CAAC,CAAC;YACP,CAAC;YACD,SAAS;QACb,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACzB,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;YACnD,SAAS;QACb,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC3B,MAAM,CAAC,IAAI,CAAC;gBACR,IAAI,EAAE,UAAU;gBAChB,KAAK,EAAE,IAAI,CAAC,KAA8B;aAC7C,CAAC,CAAC;YACH,SAAS;QACb,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YACxB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC9E,CAAC;IACL,CAAC;IAED,OAAO,MAAM,CAAC;AAClB,CAAC;AAOD;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAC9B,UAAkB,EAClB,UAAuB;IAEvB,IAAI,UAAU,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACrD,CAAC;IACD,MAAM,aAAa,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC;IAC1E,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,KAAK,MAAM,KAAK,IAAI,aAAa,EAAE,CAAC;YAChC,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC;gBACvC,SAAS;YACb,CAAC;YACD,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;YACrD,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;gBACnB,SAAS;YACb,CAAC;YACD,MAAM,WAAW,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACtC,IAAI,WAAW,KAAK,SAAS,IAAI,gBAAgB,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;gBAClE,SAAS;YACb,CAAC;YACD,MAAM,SAAS,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC;YACnC,KAAK,MAAM,KAAK,IAAI,aAAa,EAAE,CAAC;gBAChC,IAAI,SAAS,GAAG,KAAK,CAAC,MAAM,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC;oBAC/C,SAAS;gBACb,CAAC;gBACD,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,SAAS,EAAE,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;gBACrE,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;oBACnB,SAAS;gBACb,CAAC;gBACD,MAAM,WAAW,GAAG,UAAU,CAAC,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;gBACzD,IAAI,WAAW,KAAK,SAAS,IAAI,gBAAgB,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;oBAClE,SAAS;gBACb,CAAC;gBACD,MAAM,UAAU,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;gBACxE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,CAAC;YACjE,CAAC;QACL,CAAC;IACL,CAAC;IACD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACrD,CAAC"}
1
+ {"version":3,"file":"expression.utils.js","sourceRoot":"","sources":["../../../src/utils/formula/expression.utils.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAsC;;IACrE,IAAI,CAAC,CAAA,MAAA,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,MAAM,0CAAE,MAAM,CAAA,EAAE,CAAC;QAC3B,OAAO,EAAE,CAAC;IACd,CAAC;IACD,OAAO,OAAO,CAAC,MAAM;SAChB,GAAG,CAAC,CAAC,CAAC,EAAE;QACL,IAAI,CAAC,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YACrB,OAAO,CAAC,CAAC,IAAI,CAAC;QAClB,CAAC;QACD,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtB,OAAO,GAAG,CAAC;QACf,CAAC;QACD,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtB,OAAO,GAAG,CAAC;QACf,CAAC;QACD,OAAO,CAAC,CAAC,KAAK,CAAC;IACnB,CAAC,CAAC;SACD,IAAI,CAAC,GAAG,CAAC;SACT,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC;SACpB,IAAI,EAAE,CAAC;AAChB,CAAC;AAQD,6EAA6E;AAC7E,MAAM,gBAAgB,GAAG,yDAAyD,CAAC;AAEnF,MAAM,UAAU,kBAAkB,CAAC,UAAkB;IACjD,MAAM,MAAM,GAAqB,EAAE,CAAC;IACpC,IAAI,KAA6B,CAAC;IAClC,OAAO,CAAC,KAAK,GAAG,gBAAgB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC1D,MAAM,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACvB,IAAI,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3B,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QAC1C,CAAC;aAAM,IAAI,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAC3B,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;QAC3C,CAAC;aAAM,IAAI,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACnC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,KAAK,KAAK,GAAG,IAAI,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,EAAE,KAAK,EAAE,CAAC,CAAC;QACxF,CAAC;aAAM,CAAC;YACJ,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;QACzC,CAAC;IACL,CAAC;IACD,OAAO,MAAM,CAAC;AAClB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC3B,UAAkB,EAClB,UAAuB,EACvB,eAA6B;IAE7B,MAAM,KAAK,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC,MAAM,CAC/C,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,CAClD,CAAC;IACF,MAAM,MAAM,GAAmB,EAAE,CAAC;IAElC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,IAAI,IAAI,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;YACvB,SAAS;QACb,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YACxB,IAAI,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC7B,MAAM,SAAS,GAAG,CAAA,eAAe,aAAf,eAAe,uBAAf,eAAe,CAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,EAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC;gBACvE,MAAM,CAAC,IAAI,CAAC;oBACR,IAAI,EAAE,OAAO;oBACb,IAAI,EAAE,IAAI,CAAC,KAAK;oBAChB,SAAS;iBACZ,CAAC,CAAC;YACP,CAAC;YACD,SAAS;QACb,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACzB,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;YACnD,SAAS;QACb,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAC3B,MAAM,CAAC,IAAI,CAAC;gBACR,IAAI,EAAE,UAAU;gBAChB,KAAK,EAAE,IAAI,CAAC,KAA8B;aAC7C,CAAC,CAAC;YACH,SAAS;QACb,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;YACxB,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC9E,CAAC;IACL,CAAC;IAED,OAAO,MAAM,CAAC;AAClB,CAAC;AAOD;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAC9B,UAAkB,EAClB,UAAuB;IAEvB,IAAI,UAAU,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;IACrD,CAAC;IACD,MAAM,aAAa,GAAG,CAAC,GAAG,UAAU,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC;IAC1E,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACzC,KAAK,MAAM,KAAK,IAAI,aAAa,EAAE,CAAC;YAChC,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC;gBACvC,SAAS;YACb,CAAC;YACD,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;YACrD,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;gBACnB,SAAS;YACb,CAAC;YACD,MAAM,WAAW,GAAG,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YACtC,IAAI,WAAW,KAAK,SAAS,IAAI,gBAAgB,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;gBAClE,SAAS;YACb,CAAC;YACD,MAAM,SAAS,GAAG,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC;YACnC,KAAK,MAAM,KAAK,IAAI,aAAa,EAAE,CAAC;gBAChC,IAAI,SAAS,GAAG,KAAK,CAAC,MAAM,GAAG,UAAU,CAAC,MAAM,EAAE,CAAC;oBAC/C,SAAS;gBACb,CAAC;gBACD,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,SAAS,EAAE,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;gBACrE,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;oBACnB,SAAS;gBACb,CAAC;gBACD,MAAM,WAAW,GAAG,UAAU,CAAC,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC;gBACzD,IAAI,WAAW,KAAK,SAAS,IAAI,gBAAgB,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;oBAClE,SAAS;gBACb,CAAC;gBACD,MAAM,UAAU,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;gBACxE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,CAAC;YACjE,CAAC;QACL,CAAC;IACL,CAAC;IACD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AACrD,CAAC"}
@@ -3,5 +3,5 @@ import { CalculatedFieldFormat } from '../../interface/types';
3
3
  * Format a calculated formula result for display using advanced settings.
4
4
  * Applies rounding, decimal places, thousands/decimal separators, result type (number/currency/percent/date), and prefix/postfix.
5
5
  */
6
- export declare function formatCalculatedResult(value: number, format: CalculatedFieldFormat | undefined): string;
6
+ export declare const formatCalculatedResult: (value: number, format: CalculatedFieldFormat | undefined) => string;
7
7
  //# sourceMappingURL=format-calculated-result.utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"format-calculated-result.utils.d.ts","sourceRoot":"","sources":["../../../src/utils/formula/format-calculated-result.utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AA8D9D;;;GAGG;AACH,wBAAgB,sBAAsB,CAClC,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,qBAAqB,GAAG,SAAS,GAC1C,MAAM,CA8BR"}
1
+ {"version":3,"file":"format-calculated-result.utils.d.ts","sourceRoot":"","sources":["../../../src/utils/formula/format-calculated-result.utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAA6B,MAAM,uBAAuB,CAAC;AA2EzF;;;GAGG;AACH,eAAO,MAAM,sBAAsB,GAC/B,OAAO,MAAM,EACb,QAAQ,qBAAqB,GAAG,SAAS,KAC1C,MAiCF,CAAC"}
@@ -1,5 +1,5 @@
1
- import { DEFAULT_DATE_FORMAT } from '../../constants';
2
- function roundValue(value, decimals, mode) {
1
+ import { DEFAULT_DATE_FORMAT, MAX_DATE_DISPLAY_RANGE_YEARS } from '../../constants';
2
+ const roundValue = (value, decimals, mode) => {
3
3
  const factor = 10 ** decimals;
4
4
  const scaled = value * factor;
5
5
  switch (mode) {
@@ -10,8 +10,8 @@ function roundValue(value, decimals, mode) {
10
10
  default:
11
11
  return Math.round(scaled) / factor;
12
12
  }
13
- }
14
- function formatIntegerPart(s, thousandsSeparator, decimalSeparator) {
13
+ };
14
+ const formatIntegerPart = (s, thousandsSeparator, decimalSeparator) => {
15
15
  if (!thousandsSeparator) {
16
16
  return s;
17
17
  }
@@ -24,7 +24,7 @@ function formatIntegerPart(s, thousandsSeparator, decimalSeparator) {
24
24
  i = start;
25
25
  }
26
26
  return parts.join(sep);
27
- }
27
+ };
28
28
  const DATE_FORMAT_TOKENS = {
29
29
  YYYY: d => String(d.getFullYear()),
30
30
  YY: d => String(d.getFullYear()).slice(-2),
@@ -36,7 +36,7 @@ const DATE_FORMAT_TOKENS = {
36
36
  D: d => String(d.getDate()),
37
37
  };
38
38
  const DATE_TOKEN_PATTERN = new RegExp(Object.keys(DATE_FORMAT_TOKENS).join('|'), 'g');
39
- function formatDateValue(epochMs, dateFormat) {
39
+ const formatDateValue = (epochMs, dateFormat) => {
40
40
  const date = new Date(epochMs);
41
41
  if (isNaN(date.getTime())) {
42
42
  return '';
@@ -45,17 +45,32 @@ function formatDateValue(epochMs, dateFormat) {
45
45
  const fn = DATE_FORMAT_TOKENS[match];
46
46
  return fn ? fn(date) : match;
47
47
  });
48
- }
48
+ };
49
+ const isDateWithinDisplayRange = (epochMs, referenceMs = Date.now()) => {
50
+ const date = new Date(epochMs);
51
+ if (isNaN(date.getTime())) {
52
+ return false;
53
+ }
54
+ const ref = new Date(referenceMs);
55
+ const min = new Date(ref);
56
+ min.setFullYear(min.getFullYear() - MAX_DATE_DISPLAY_RANGE_YEARS);
57
+ const max = new Date(ref);
58
+ max.setFullYear(max.getFullYear() + MAX_DATE_DISPLAY_RANGE_YEARS);
59
+ return date >= min && date <= max;
60
+ };
49
61
  /**
50
62
  * Format a calculated formula result for display using advanced settings.
51
63
  * Applies rounding, decimal places, thousands/decimal separators, result type (number/currency/percent/date), and prefix/postfix.
52
64
  */
53
- export function formatCalculatedResult(value, format) {
65
+ export const formatCalculatedResult = (value, format) => {
54
66
  var _a;
55
67
  if (format == null) {
56
68
  return String(value);
57
69
  }
58
70
  if (format.resultType === 'date') {
71
+ if (!isDateWithinDisplayRange(value)) {
72
+ return '';
73
+ }
59
74
  return formatDateValue(value, (_a = format.dateFormat) !== null && _a !== void 0 ? _a : DEFAULT_DATE_FORMAT);
60
75
  }
61
76
  const { decimalSeparator, decimalSeparatorEnabled, decimals, postfixText, prefixText, roundingMode, thousandsSeparator, } = format;
@@ -67,5 +82,5 @@ export function formatCalculatedResult(value, format) {
67
82
  const decSuffix = decimals > 0 ? decimalSep + (decPart !== null && decPart !== void 0 ? decPart : '') : '';
68
83
  const numberStr = intFormatted + decSuffix;
69
84
  return `${prefixText}${numberStr}${postfixText}`;
70
- }
85
+ };
71
86
  //# sourceMappingURL=format-calculated-result.utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"format-calculated-result.utils.js","sourceRoot":"","sources":["../../../src/utils/formula/format-calculated-result.utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"format-calculated-result.utils.js","sourceRoot":"","sources":["../../../src/utils/formula/format-calculated-result.utils.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@servicetitan/dte-pdf-editor",
3
- "version": "1.38.0",
3
+ "version": "1.40.0",
4
4
  "description": "",
5
5
  "main": "./dist/index.js",
6
6
  "typings": "./dist/index.d.ts",
@@ -1,19 +1,13 @@
1
1
  import { Flex, SegmentedControl, Switch, Text } from '@servicetitan/anvil2';
2
2
  import { Dispatch, FC, SetStateAction } from 'react';
3
- import { DEFAULT_DATE_FORMAT } from '../../constants';
4
- import { CalculatedFieldFormat } from '../../interface/types';
3
+ import { DEFAULT_DATE_FORMAT, ROUNDING_OPTIONS } from '../../constants';
4
+ import { CalculatedFieldFormat, CalculatedFormatForNumber } from '../../interface/types';
5
5
 
6
6
  interface AdvancedSettingsProps {
7
7
  format: CalculatedFieldFormat;
8
8
  setFormat: Dispatch<SetStateAction<CalculatedFieldFormat>>;
9
9
  }
10
10
 
11
- const ROUNDING_OPTIONS: { label: string; value: CalculatedFieldFormat['roundingMode'] }[] = [
12
- { label: 'Round', value: 'round' },
13
- { label: 'Floor', value: 'floor' },
14
- { label: 'Ceil', value: 'ceil' },
15
- ];
16
-
17
11
  const DateFormatSettings: FC<AdvancedSettingsProps> = ({ format, setFormat }) => (
18
12
  <div className="dte-formula-advanced">
19
13
  <Text variant="body" size="small">
@@ -46,7 +40,7 @@ export const AdvancedSettings: FC<AdvancedSettingsProps> = ({ format, setFormat
46
40
  </Text>
47
41
  <SegmentedControl
48
42
  selected={format.roundingMode}
49
- onChange={(roundingMode: CalculatedFieldFormat['roundingMode']) =>
43
+ onChange={(roundingMode: CalculatedFormatForNumber['roundingMode']) =>
50
44
  setFormat(prev => ({ ...prev, roundingMode }))
51
45
  }
52
46
  fill
@@ -88,7 +82,7 @@ export const AdvancedSettings: FC<AdvancedSettingsProps> = ({ format, setFormat
88
82
  size="small"
89
83
  fill
90
84
  selected={format.decimalSeparator}
91
- onChange={(decimalSeparator: CalculatedFieldFormat['decimalSeparator']) =>
85
+ onChange={(decimalSeparator: CalculatedFormatForNumber['decimalSeparator']) =>
92
86
  setFormat(prev => ({ ...prev, decimalSeparator }))
93
87
  }
94
88
  >
@@ -2,7 +2,11 @@ import { Button, Dialog, Divider, Flex } from '@servicetitan/anvil2';
2
2
  import IconRedo from '@servicetitan/anvil2/assets/icons/material/round/redo.svg';
3
3
  import IconUndo from '@servicetitan/anvil2/assets/icons/material/round/undo.svg';
4
4
  import { FC, useCallback, useEffect, useMemo, useState } from 'react';
5
- import { DEFAULT_DATE_FORMAT, MODAL_CONTENT_MAX_HEIGHT } from '../../constants';
5
+ import {
6
+ DEFAULT_DATE_CALCULATED_FORMAT,
7
+ DEFAULT_NUMBER_FORMAT,
8
+ MODAL_CONTENT_MAX_HEIGHT,
9
+ } from '../../constants';
6
10
  import { useFormulaEditor } from '../../hooks';
7
11
  import {
8
12
  CalculatedFieldFormat,
@@ -19,17 +23,6 @@ import {
19
23
  import { FieldSidebar } from './field-sidebar';
20
24
  import { FormulaWorkspace } from './formula-workspace';
21
25
 
22
- const DEFAULT_CALCULATED_FIELD_FORMAT: CalculatedFieldFormat = {
23
- resultType: 'number',
24
- thousandsSeparator: false,
25
- decimals: 2,
26
- roundingMode: 'round',
27
- decimalSeparatorEnabled: false,
28
- decimalSeparator: '.',
29
- prefixText: '',
30
- postfixText: '',
31
- };
32
-
33
26
  function getAllFields(groups: DataModelFieldGroup[]): FieldTypeOption[] {
34
27
  const list: FieldTypeOption[] = [];
35
28
  for (const g of groups) {
@@ -111,7 +104,7 @@ export const FormulaModal: FC<FormulaModalProps> = ({
111
104
 
112
105
  const [highlightElementPath, setHighlightElementPath] = useState('');
113
106
  const [format, setFormat] = useState<CalculatedFieldFormat>(
114
- () => initialFormat ?? DEFAULT_CALCULATED_FIELD_FORMAT,
107
+ () => initialFormat ?? DEFAULT_NUMBER_FORMAT,
115
108
  );
116
109
  const [advancedOpen, setAdvancedOpen] = useState(false);
117
110
 
@@ -124,23 +117,15 @@ export const FormulaModal: FC<FormulaModalProps> = ({
124
117
 
125
118
  useEffect(() => {
126
119
  if (formulaEditor.expressionHasDateFields && format.resultType !== 'date') {
127
- setFormat(prev => ({
128
- ...prev,
129
- resultType: 'date',
130
- dateFormat: prev.dateFormat ?? DEFAULT_DATE_FORMAT,
131
- }));
132
- setAdvancedOpen(true);
120
+ setFormat(DEFAULT_DATE_CALCULATED_FORMAT);
133
121
  } else if (!formulaEditor.expressionHasDateFields && format.resultType === 'date') {
134
- setFormat(prev => ({
135
- ...prev,
136
- resultType: 'number',
137
- }));
122
+ setFormat(DEFAULT_NUMBER_FORMAT);
138
123
  }
139
124
  }, [formulaEditor.expressionHasDateFields, format.resultType]);
140
125
 
141
126
  const parsedTokens = useMemo(
142
- () => parseExpression(formulaEditor.draftExpression, validPaths),
143
- [formulaEditor.draftExpression, validPaths],
127
+ () => parseExpression(formulaEditor.draftExpression, validPaths, knownDateFields),
128
+ [formulaEditor.draftExpression, validPaths, knownDateFields],
144
129
  );
145
130
 
146
131
  const formulaValidation = useMemo(
@@ -164,16 +149,9 @@ export const FormulaModal: FC<FormulaModalProps> = ({
164
149
  }, [onClose]);
165
150
 
166
151
  const handleSave = useCallback(() => {
167
- const usedDatePaths = parsedTokens
168
- .filter(t => t.type === 'field' && knownDateFields.has(t.path))
169
- .map(t => (t as { type: 'field'; path: string }).path);
170
- const savedFormat: CalculatedFieldFormat = {
171
- ...format,
172
- dateFieldPaths: usedDatePaths.length > 0 ? [...new Set(usedDatePaths)] : undefined,
173
- };
174
- onSave({ tokens: parsedTokens }, savedFormat);
152
+ onSave({ tokens: parsedTokens }, format);
175
153
  onClose();
176
- }, [format, knownDateFields, onClose, onSave, parsedTokens]);
154
+ }, [format, onClose, onSave, parsedTokens]);
177
155
 
178
156
  const validationError = unknownFieldErrors[0] ?? formulaValidation.errors[0] ?? '';
179
157
  const isInvalid = !formulaValidation.valid || unknownFieldErrors.length > 0;
@@ -208,14 +186,18 @@ export const FormulaModal: FC<FormulaModalProps> = ({
208
186
  isInvalid={isInvalid && formulaEditor.isDirty}
209
187
  validationError={validationError}
210
188
  format={format}
211
- onResultTypeChange={nextType =>
212
- setFormat(prev => ({
213
- ...prev,
214
- resultType: nextType,
215
- prefixText: nextType === 'currency' ? '$' : '',
216
- postfixText: nextType === 'percent' ? '%' : '',
217
- }))
218
- }
189
+ onResultTypeChange={nextType => {
190
+ if (nextType === 'date') {
191
+ setFormat(DEFAULT_DATE_CALCULATED_FORMAT);
192
+ } else {
193
+ setFormat({
194
+ ...DEFAULT_NUMBER_FORMAT,
195
+ resultType: nextType,
196
+ prefixText: nextType === 'currency' ? '$' : '',
197
+ postfixText: nextType === 'percent' ? '%' : '',
198
+ });
199
+ }
200
+ }}
219
201
  advancedOpen={advancedOpen}
220
202
  onToggleAdvanced={() => setAdvancedOpen(prev => !prev)}
221
203
  setFormat={setFormat}
@@ -9,14 +9,9 @@ interface PdfViewCalculatedProps {
9
9
  }
10
10
 
11
11
  export const PdfViewCalculated: FC<PdfViewCalculatedProps> = ({ data, field, holidays }) => {
12
- const dateFieldPaths = useMemo(() => {
13
- const paths = field.formulaFormat?.dateFieldPaths;
14
- return paths?.length ? new Set(paths) : undefined;
15
- }, [field.formulaFormat?.dateFieldPaths]);
16
-
17
12
  const displayValue = useMemo(() => {
18
13
  if (field.formula?.tokens?.length) {
19
- const value = evaluateFormula(field.formula, data, dateFieldPaths, holidays);
14
+ const value = evaluateFormula(field.formula, data, holidays);
20
15
  if (value === null) {
21
16
  return '';
22
17
  }
@@ -26,15 +21,7 @@ export const PdfViewCalculated: FC<PdfViewCalculatedProps> = ({ data, field, hol
26
21
  return resolvePdfDataValues(data, field.path) ?? '';
27
22
  }
28
23
  return field.label ?? '';
29
- }, [
30
- data,
31
- dateFieldPaths,
32
- field.formula,
33
- field.formulaFormat,
34
- field.label,
35
- field.path,
36
- holidays,
37
- ]);
24
+ }, [data, field.formula, field.formulaFormat, field.label, field.path, holidays]);
38
25
 
39
26
  return <div className="dte-pdf-field-value">{displayValue}</div>;
40
27
  };
@@ -3,3 +3,5 @@ export const CALCULATED_OPERATIONS = ['+', '-', '*', '/', '(', ')'];
3
3
  export const DEFAULT_DATE_FORMAT = 'MM/DD/YYYY';
4
4
 
5
5
  export const MAX_DATE_CALC_DAYS = 365;
6
+
7
+ export const MAX_DATE_DISPLAY_RANGE_YEARS = 2;
@@ -1,9 +1,12 @@
1
1
  import {
2
+ CalculatedFormatForDate,
3
+ CalculatedFormatForNumber,
2
4
  ESignFieldType,
3
5
  FieldTypeEnum,
4
6
  FieldTypeOption,
5
7
  PdfFieldSubType,
6
8
  } from '../interface/types';
9
+ import { DEFAULT_DATE_FORMAT } from './calculated.constants';
7
10
  import { BASE_PAGE_WIDTH } from './pdf-editor.constants';
8
11
 
9
12
  export const FIELD_CONSTANTS = {
@@ -82,3 +85,28 @@ export const DISABLE_FIELD_RESIZE = {
82
85
  FieldTypeEnum,
83
86
  Partial<Record<PdfFieldSubType, { disableHorizontal?: boolean; disableVertical?: boolean }>>
84
87
  >;
88
+
89
+ export const ROUNDING_OPTIONS = [
90
+ { label: 'Round', value: 'round' },
91
+ { label: 'Floor', value: 'floor' },
92
+ { label: 'Ceil', value: 'ceil' },
93
+ ] as {
94
+ label: string;
95
+ value: CalculatedFormatForNumber['roundingMode'];
96
+ }[];
97
+
98
+ export const DEFAULT_NUMBER_FORMAT: CalculatedFormatForNumber = {
99
+ resultType: 'number',
100
+ thousandsSeparator: false,
101
+ decimals: 2,
102
+ roundingMode: 'round',
103
+ decimalSeparatorEnabled: false,
104
+ decimalSeparator: '.',
105
+ prefixText: '',
106
+ postfixText: '',
107
+ };
108
+
109
+ export const DEFAULT_DATE_CALCULATED_FORMAT: CalculatedFormatForDate = {
110
+ resultType: 'date',
111
+ dateFormat: DEFAULT_DATE_FORMAT,
112
+ };
@@ -105,16 +105,16 @@ export type FormulaToken =
105
105
  | { type: 'operator'; value: FormulaOperator }
106
106
  | { type: 'lparen' }
107
107
  | { type: 'rparen' }
108
- | { type: 'field'; path: string };
108
+ | { type: 'field'; path: string; fieldType: SchemaFieldType };
109
109
 
110
110
  /** Structured formula representation (AST-like token list) for validation and safe editing */
111
111
  export interface StructuredFormula {
112
112
  tokens: FormulaToken[];
113
113
  }
114
114
 
115
- /** Format options for a calculated field result (display and rounding) */
116
- export interface CalculatedFieldFormat {
117
- resultType: 'number' | 'currency' | 'percent' | 'date';
115
+ /** Format options for a calculated field with a numeric result (number, currency, percent) */
116
+ export interface CalculatedFormatForNumber {
117
+ resultType: 'number' | 'currency' | 'percent';
118
118
  thousandsSeparator: boolean;
119
119
  decimals: number;
120
120
  roundingMode: 'round' | 'floor' | 'ceil';
@@ -123,10 +123,17 @@ export interface CalculatedFieldFormat {
123
123
  prefixText: string;
124
124
  postfixText: string;
125
125
  dateFormat?: string;
126
- /** Paths of date-typed fields used in the formula, persisted for date-aware evaluation */
127
- dateFieldPaths?: string[];
128
126
  }
129
127
 
128
+ /** Format options for a calculated field with a date result */
129
+ export interface CalculatedFormatForDate {
130
+ resultType: 'date';
131
+ dateFormat: string;
132
+ }
133
+
134
+ /** Format options for a calculated field result (display and rounding) */
135
+ export type CalculatedFieldFormat = CalculatedFormatForDate | CalculatedFormatForNumber;
136
+
130
137
  export interface SchemaFieldBaseOptions {
131
138
  placeholder?: any;
132
139
  description?: any;
@@ -28,10 +28,20 @@ export function valueToNumber(raw: unknown): number {
28
28
  return Number.isNaN(n) ? 0 : n;
29
29
  }
30
30
 
31
+ function collectDateFieldPaths(formula: StructuredFormula): Set<string> {
32
+ const set = new Set<string>();
33
+ for (const t of formula.tokens) {
34
+ if (t.type === 'field' && t.fieldType === 'date') {
35
+ set.add(t.path);
36
+ }
37
+ }
38
+ return set;
39
+ }
40
+
31
41
  function hasAllFieldValues(
32
42
  formula: StructuredFormula,
33
43
  data: DataModelValues | undefined,
34
- dateFieldPaths?: Set<string>,
44
+ dateFieldPaths: Set<string>,
35
45
  ): boolean {
36
46
  return formula.tokens.every((t: FormulaToken) => {
37
47
  if (t.type !== 'field') {
@@ -41,7 +51,7 @@ function hasAllFieldValues(
41
51
  if (raw === '') {
42
52
  return false;
43
53
  }
44
- if (dateFieldPaths?.has(t.path)) {
54
+ if (dateFieldPaths.has(t.path)) {
45
55
  return !isNaN(new Date(raw).getTime());
46
56
  }
47
57
  return !isNaN(Number(raw.trim()));
@@ -282,12 +292,11 @@ function businessDayDiff(fromMs: number, toMs: number, holidaySet: Set<string>):
282
292
  function resolveDateAwareTokens(
283
293
  formula: StructuredFormula,
284
294
  data: DataModelValues | undefined,
285
- dateFieldPaths: Set<string>,
286
295
  ): DateAwareToken[] {
287
296
  return formula.tokens.map((t: FormulaToken): DateAwareToken => {
288
297
  if (t.type === 'field') {
289
298
  const raw = resolvePdfDataValues(data, t.path);
290
- if (dateFieldPaths.has(t.path)) {
299
+ if (t.fieldType === 'date') {
291
300
  const ms = parseDateValue(raw);
292
301
  return { kind: 'date', value: isNaN(ms) ? 0 : ms };
293
302
  }
@@ -395,26 +404,28 @@ function evalDateAwareTokens(tokens: DateAwareToken[], holidaySet: Set<string>):
395
404
  * to null / undefined / empty / non-numeric (non-date) — making the entire
396
405
  * calculation blank instead of silently substituting 0.
397
406
  *
398
- * When `dateFieldPaths` is provided, date fields are resolved to epoch-ms and
399
- * arithmetic follows business-day semantics — weekends and holidays are skipped
400
- * when adding/subtracting days, and date diffs count only business days.
407
+ * Date fields are identified by `fieldType: 'date'` on field tokens. When date
408
+ * fields are present, arithmetic follows business-day semantics — weekends and
409
+ * holidays are skipped when adding/subtracting days, and date diffs count only
410
+ * business days.
401
411
  */
402
412
  export function evaluateFormula(
403
413
  formula: StructuredFormula | undefined | null,
404
414
  data: DataModelValues | undefined,
405
- dateFieldPaths?: Set<string>,
406
415
  holidays?: string[],
407
416
  ): number | null {
408
417
  if (!formula?.tokens?.length) {
409
418
  return null;
410
419
  }
411
420
 
421
+ const dateFieldPaths = collectDateFieldPaths(formula);
422
+
412
423
  if (!hasAllFieldValues(formula, data, dateFieldPaths)) {
413
424
  return null;
414
425
  }
415
426
 
416
- if (dateFieldPaths?.size) {
417
- const resolved = resolveDateAwareTokens(formula, data, dateFieldPaths);
427
+ if (dateFieldPaths.size) {
428
+ const resolved = resolveDateAwareTokens(formula, data);
418
429
  const holidaySet = buildHolidaySet(holidays);
419
430
  const result = evalDateAwareTokens(resolved, holidaySet);
420
431
  return result.value;
@@ -57,7 +57,11 @@ export function tokenizeExpression(expression: string): ExpressionPart[] {
57
57
  * Parse an expression string into FormulaToken[] using valid paths.
58
58
  * Invalid or unknown identifiers are skipped; only known paths become field tokens.
59
59
  */
60
- export function parseExpression(expression: string, validPaths: Set<string>): FormulaToken[] {
60
+ export function parseExpression(
61
+ expression: string,
62
+ validPaths: Set<string>,
63
+ knownDateFields?: Set<string>,
64
+ ): FormulaToken[] {
61
65
  const parts = tokenizeExpression(expression).filter(
62
66
  p => p.type !== 'text' || p.value.trim() !== '',
63
67
  );
@@ -69,9 +73,11 @@ export function parseExpression(expression: string, validPaths: Set<string>): Fo
69
73
  }
70
74
  if (part.type === 'field') {
71
75
  if (validPaths.has(part.value)) {
76
+ const fieldType = knownDateFields?.has(part.value) ? 'date' : 'number';
72
77
  tokens.push({
73
78
  type: 'field',
74
79
  path: part.value,
80
+ fieldType,
75
81
  });
76
82
  }
77
83
  continue;