@fieldia/core 0.1.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 (130) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +31 -0
  3. package/package.json +40 -0
  4. package/schema/page.schema.json +2142 -0
  5. package/src/index.d.mts +15 -0
  6. package/src/index.d.ts +15 -0
  7. package/src/index.js +46 -0
  8. package/src/index.js.map +1 -0
  9. package/src/index.mjs +14 -0
  10. package/src/index.mjs.map +1 -0
  11. package/src/lib/expression/evaluateModifier.d.mts +55 -0
  12. package/src/lib/expression/evaluateModifier.d.ts +55 -0
  13. package/src/lib/expression/evaluateModifier.js +121 -0
  14. package/src/lib/expression/evaluateModifier.js.map +1 -0
  15. package/src/lib/expression/evaluateModifier.mjs +117 -0
  16. package/src/lib/expression/evaluateModifier.mjs.map +1 -0
  17. package/src/lib/expression/evaluator.d.mts +23 -0
  18. package/src/lib/expression/evaluator.d.ts +23 -0
  19. package/src/lib/expression/evaluator.js +122 -0
  20. package/src/lib/expression/evaluator.js.map +1 -0
  21. package/src/lib/expression/evaluator.mjs +118 -0
  22. package/src/lib/expression/evaluator.mjs.map +1 -0
  23. package/src/lib/expression/extractFieldNames.d.mts +41 -0
  24. package/src/lib/expression/extractFieldNames.d.ts +41 -0
  25. package/src/lib/expression/extractFieldNames.js +97 -0
  26. package/src/lib/expression/extractFieldNames.js.map +1 -0
  27. package/src/lib/expression/extractFieldNames.mjs +93 -0
  28. package/src/lib/expression/extractFieldNames.mjs.map +1 -0
  29. package/src/lib/expression/modifier.d.mts +14 -0
  30. package/src/lib/expression/modifier.d.ts +14 -0
  31. package/src/lib/expression/modifier.js +55 -0
  32. package/src/lib/expression/modifier.js.map +1 -0
  33. package/src/lib/expression/modifier.mjs +52 -0
  34. package/src/lib/expression/modifier.mjs.map +1 -0
  35. package/src/lib/expression/parser.d.mts +109 -0
  36. package/src/lib/expression/parser.d.ts +109 -0
  37. package/src/lib/expression/parser.js +317 -0
  38. package/src/lib/expression/parser.js.map +1 -0
  39. package/src/lib/expression/parser.mjs +313 -0
  40. package/src/lib/expression/parser.mjs.map +1 -0
  41. package/src/lib/expression/tokenizer.d.mts +31 -0
  42. package/src/lib/expression/tokenizer.d.ts +31 -0
  43. package/src/lib/expression/tokenizer.js +100 -0
  44. package/src/lib/expression/tokenizer.js.map +1 -0
  45. package/src/lib/expression/tokenizer.mjs +96 -0
  46. package/src/lib/expression/tokenizer.mjs.map +1 -0
  47. package/src/lib/format/field.d.mts +967 -0
  48. package/src/lib/format/field.d.ts +967 -0
  49. package/src/lib/format/field.js +147 -0
  50. package/src/lib/format/field.js.map +1 -0
  51. package/src/lib/format/field.mjs +144 -0
  52. package/src/lib/format/field.mjs.map +1 -0
  53. package/src/lib/format/json-schema.d.mts +6 -0
  54. package/src/lib/format/json-schema.d.ts +6 -0
  55. package/src/lib/format/json-schema.js +14 -0
  56. package/src/lib/format/json-schema.js.map +1 -0
  57. package/src/lib/format/json-schema.mjs +11 -0
  58. package/src/lib/format/json-schema.mjs.map +1 -0
  59. package/src/lib/format/json.d.mts +7 -0
  60. package/src/lib/format/json.d.ts +7 -0
  61. package/src/lib/format/json.js +7 -0
  62. package/src/lib/format/json.js.map +1 -0
  63. package/src/lib/format/json.mjs +4 -0
  64. package/src/lib/format/json.mjs.map +1 -0
  65. package/src/lib/format/layout.d.mts +521 -0
  66. package/src/lib/format/layout.d.ts +521 -0
  67. package/src/lib/format/layout.js +150 -0
  68. package/src/lib/format/layout.js.map +1 -0
  69. package/src/lib/format/layout.mjs +147 -0
  70. package/src/lib/format/layout.mjs.map +1 -0
  71. package/src/lib/format/layout.types.d.mts +22 -0
  72. package/src/lib/format/layout.types.d.ts +22 -0
  73. package/src/lib/format/layout.types.js +3 -0
  74. package/src/lib/format/layout.types.js.map +1 -0
  75. package/src/lib/format/layout.types.mjs +2 -0
  76. package/src/lib/format/layout.types.mjs.map +1 -0
  77. package/src/lib/format/page.d.mts +511 -0
  78. package/src/lib/format/page.d.ts +511 -0
  79. package/src/lib/format/page.js +27 -0
  80. package/src/lib/format/page.js.map +1 -0
  81. package/src/lib/format/page.mjs +24 -0
  82. package/src/lib/format/page.mjs.map +1 -0
  83. package/src/lib/format/validate.d.mts +23 -0
  84. package/src/lib/format/validate.d.ts +23 -0
  85. package/src/lib/format/validate.js +210 -0
  86. package/src/lib/format/validate.js.map +1 -0
  87. package/src/lib/format/validate.mjs +207 -0
  88. package/src/lib/format/validate.mjs.map +1 -0
  89. package/src/lib/record/check.d.mts +14 -0
  90. package/src/lib/record/check.d.ts +14 -0
  91. package/src/lib/record/check.js +167 -0
  92. package/src/lib/record/check.js.map +1 -0
  93. package/src/lib/record/check.mjs +163 -0
  94. package/src/lib/record/check.mjs.map +1 -0
  95. package/src/lib/record/data-source.d.mts +109 -0
  96. package/src/lib/record/data-source.d.ts +109 -0
  97. package/src/lib/record/data-source.js +3 -0
  98. package/src/lib/record/data-source.js.map +1 -0
  99. package/src/lib/record/data-source.mjs +2 -0
  100. package/src/lib/record/data-source.mjs.map +1 -0
  101. package/src/lib/record/form.d.mts +106 -0
  102. package/src/lib/record/form.d.ts +106 -0
  103. package/src/lib/record/form.js +545 -0
  104. package/src/lib/record/form.js.map +1 -0
  105. package/src/lib/record/form.mjs +542 -0
  106. package/src/lib/record/form.mjs.map +1 -0
  107. package/src/lib/record/memory-data-source.d.mts +28 -0
  108. package/src/lib/record/memory-data-source.d.ts +28 -0
  109. package/src/lib/record/memory-data-source.js +132 -0
  110. package/src/lib/record/memory-data-source.js.map +1 -0
  111. package/src/lib/record/memory-data-source.mjs +129 -0
  112. package/src/lib/record/memory-data-source.mjs.map +1 -0
  113. package/src/lib/record/messages.d.mts +35 -0
  114. package/src/lib/record/messages.d.ts +35 -0
  115. package/src/lib/record/messages.js +111 -0
  116. package/src/lib/record/messages.js.map +1 -0
  117. package/src/lib/record/messages.mjs +107 -0
  118. package/src/lib/record/messages.mjs.map +1 -0
  119. package/src/lib/record/scheduler.d.mts +12 -0
  120. package/src/lib/record/scheduler.d.ts +12 -0
  121. package/src/lib/record/scheduler.js +16 -0
  122. package/src/lib/record/scheduler.js.map +1 -0
  123. package/src/lib/record/scheduler.mjs +12 -0
  124. package/src/lib/record/scheduler.mjs.map +1 -0
  125. package/src/lib/record/values.d.mts +54 -0
  126. package/src/lib/record/values.d.ts +54 -0
  127. package/src/lib/record/values.js +78 -0
  128. package/src/lib/record/values.js.map +1 -0
  129. package/src/lib/record/values.mjs +71 -0
  130. package/src/lib/record/values.mjs.map +1 -0
@@ -0,0 +1,15 @@
1
+ export type { JsonValue } from './lib/format/json.mjs';
2
+ export { FIELD_NAME, FIELD_TYPES, FieldSchema, FieldsSchema, LineFieldSchema, OptionSchema, FilterConditionSchema, type Field, type Fields, type FieldType, type LineField, type Option, type FilterCondition, } from './lib/format/field.mjs';
3
+ export { ModifierSchema, LayoutNodeSchema, RootLayoutSchema, type Modifier, type Tone, type FieldNode, type ButtonNode, type TextNode, type SlotNode, type SectionNode, type TabNode, type TabsNode, type StepNode, type WizardNode, type SectionsNode, type SheetNode, type SheetTitle, type Statusbar, type StatButton, type Ribbon, type Alert, type LayoutNode, type RootLayout, } from './lib/format/layout.mjs';
4
+ export { FORMAT_VERSION, PageSchema, type Page, type PageData } from './lib/format/page.mjs';
5
+ export { validatePage, type PageIssue, type PageValidation } from './lib/format/validate.mjs';
6
+ export { pageJsonSchema } from './lib/format/json-schema.mjs';
7
+ export { compileModifier, type CompiledModifier } from './lib/expression/modifier.mjs';
8
+ export { evaluateModifier, isModifierValid } from './lib/expression/evaluateModifier.mjs';
9
+ export { emptyValue, initialValues, isEmpty, expressionContext, type RecordId, type RelatedRecord, type ReferenceValue, type FileValue, type Line, type Value, type Values, } from './lib/record/values.mjs';
10
+ export { checkValue, formatBytes } from './lib/record/check.mjs';
11
+ export type { DataSource, LoadRequest, SaveRequest, SaveResult, OnchangeRequest, OnchangeResult, SearchRequest, SubmitRequest, SubmitResult, ResolvedFilterCondition, RecordChanges, LineOp, LinkOp, } from './lib/record/data-source.mjs';
12
+ export { createMemoryDataSource, type MemoryDataSource, type MemoryDataSourceOptions } from './lib/record/memory-data-source.mjs';
13
+ export { hostScheduler, wait, type Scheduler } from './lib/record/scheduler.mjs';
14
+ export { createForm, type Form, type FormOptions, type FormState, type FormStatus, type NodeState, type DraftStore, type ActionRequest, } from './lib/record/form.mjs';
15
+ export { MESSAGES, fill, type Messages, type Locale } from './lib/record/messages.mjs';
package/src/index.d.ts ADDED
@@ -0,0 +1,15 @@
1
+ export type { JsonValue } from './lib/format/json';
2
+ export { FIELD_NAME, FIELD_TYPES, FieldSchema, FieldsSchema, LineFieldSchema, OptionSchema, FilterConditionSchema, type Field, type Fields, type FieldType, type LineField, type Option, type FilterCondition, } from './lib/format/field';
3
+ export { ModifierSchema, LayoutNodeSchema, RootLayoutSchema, type Modifier, type Tone, type FieldNode, type ButtonNode, type TextNode, type SlotNode, type SectionNode, type TabNode, type TabsNode, type StepNode, type WizardNode, type SectionsNode, type SheetNode, type SheetTitle, type Statusbar, type StatButton, type Ribbon, type Alert, type LayoutNode, type RootLayout, } from './lib/format/layout';
4
+ export { FORMAT_VERSION, PageSchema, type Page, type PageData } from './lib/format/page';
5
+ export { validatePage, type PageIssue, type PageValidation } from './lib/format/validate';
6
+ export { pageJsonSchema } from './lib/format/json-schema';
7
+ export { compileModifier, type CompiledModifier } from './lib/expression/modifier';
8
+ export { evaluateModifier, isModifierValid } from './lib/expression/evaluateModifier';
9
+ export { emptyValue, initialValues, isEmpty, expressionContext, type RecordId, type RelatedRecord, type ReferenceValue, type FileValue, type Line, type Value, type Values, } from './lib/record/values';
10
+ export { checkValue, formatBytes } from './lib/record/check';
11
+ export type { DataSource, LoadRequest, SaveRequest, SaveResult, OnchangeRequest, OnchangeResult, SearchRequest, SubmitRequest, SubmitResult, ResolvedFilterCondition, RecordChanges, LineOp, LinkOp, } from './lib/record/data-source';
12
+ export { createMemoryDataSource, type MemoryDataSource, type MemoryDataSourceOptions } from './lib/record/memory-data-source';
13
+ export { hostScheduler, wait, type Scheduler } from './lib/record/scheduler';
14
+ export { createForm, type Form, type FormOptions, type FormState, type FormStatus, type NodeState, type DraftStore, type ActionRequest, } from './lib/record/form';
15
+ export { MESSAGES, fill, type Messages, type Locale } from './lib/record/messages';
package/src/index.js ADDED
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fill = exports.MESSAGES = exports.createForm = exports.wait = exports.hostScheduler = exports.createMemoryDataSource = exports.formatBytes = exports.checkValue = exports.expressionContext = exports.isEmpty = exports.initialValues = exports.emptyValue = exports.isModifierValid = exports.evaluateModifier = exports.compileModifier = exports.pageJsonSchema = exports.validatePage = exports.PageSchema = exports.FORMAT_VERSION = exports.RootLayoutSchema = exports.LayoutNodeSchema = exports.ModifierSchema = exports.FilterConditionSchema = exports.OptionSchema = exports.LineFieldSchema = exports.FieldsSchema = exports.FieldSchema = exports.FIELD_TYPES = exports.FIELD_NAME = void 0;
4
+ var field_1 = require("./lib/format/field");
5
+ Object.defineProperty(exports, "FIELD_NAME", { enumerable: true, get: function () { return field_1.FIELD_NAME; } });
6
+ Object.defineProperty(exports, "FIELD_TYPES", { enumerable: true, get: function () { return field_1.FIELD_TYPES; } });
7
+ Object.defineProperty(exports, "FieldSchema", { enumerable: true, get: function () { return field_1.FieldSchema; } });
8
+ Object.defineProperty(exports, "FieldsSchema", { enumerable: true, get: function () { return field_1.FieldsSchema; } });
9
+ Object.defineProperty(exports, "LineFieldSchema", { enumerable: true, get: function () { return field_1.LineFieldSchema; } });
10
+ Object.defineProperty(exports, "OptionSchema", { enumerable: true, get: function () { return field_1.OptionSchema; } });
11
+ Object.defineProperty(exports, "FilterConditionSchema", { enumerable: true, get: function () { return field_1.FilterConditionSchema; } });
12
+ var layout_1 = require("./lib/format/layout");
13
+ Object.defineProperty(exports, "ModifierSchema", { enumerable: true, get: function () { return layout_1.ModifierSchema; } });
14
+ Object.defineProperty(exports, "LayoutNodeSchema", { enumerable: true, get: function () { return layout_1.LayoutNodeSchema; } });
15
+ Object.defineProperty(exports, "RootLayoutSchema", { enumerable: true, get: function () { return layout_1.RootLayoutSchema; } });
16
+ var page_1 = require("./lib/format/page");
17
+ Object.defineProperty(exports, "FORMAT_VERSION", { enumerable: true, get: function () { return page_1.FORMAT_VERSION; } });
18
+ Object.defineProperty(exports, "PageSchema", { enumerable: true, get: function () { return page_1.PageSchema; } });
19
+ var validate_1 = require("./lib/format/validate");
20
+ Object.defineProperty(exports, "validatePage", { enumerable: true, get: function () { return validate_1.validatePage; } });
21
+ var json_schema_1 = require("./lib/format/json-schema");
22
+ Object.defineProperty(exports, "pageJsonSchema", { enumerable: true, get: function () { return json_schema_1.pageJsonSchema; } });
23
+ var modifier_1 = require("./lib/expression/modifier");
24
+ Object.defineProperty(exports, "compileModifier", { enumerable: true, get: function () { return modifier_1.compileModifier; } });
25
+ var evaluateModifier_1 = require("./lib/expression/evaluateModifier");
26
+ Object.defineProperty(exports, "evaluateModifier", { enumerable: true, get: function () { return evaluateModifier_1.evaluateModifier; } });
27
+ Object.defineProperty(exports, "isModifierValid", { enumerable: true, get: function () { return evaluateModifier_1.isModifierValid; } });
28
+ var values_1 = require("./lib/record/values");
29
+ Object.defineProperty(exports, "emptyValue", { enumerable: true, get: function () { return values_1.emptyValue; } });
30
+ Object.defineProperty(exports, "initialValues", { enumerable: true, get: function () { return values_1.initialValues; } });
31
+ Object.defineProperty(exports, "isEmpty", { enumerable: true, get: function () { return values_1.isEmpty; } });
32
+ Object.defineProperty(exports, "expressionContext", { enumerable: true, get: function () { return values_1.expressionContext; } });
33
+ var check_1 = require("./lib/record/check");
34
+ Object.defineProperty(exports, "checkValue", { enumerable: true, get: function () { return check_1.checkValue; } });
35
+ Object.defineProperty(exports, "formatBytes", { enumerable: true, get: function () { return check_1.formatBytes; } });
36
+ var memory_data_source_1 = require("./lib/record/memory-data-source");
37
+ Object.defineProperty(exports, "createMemoryDataSource", { enumerable: true, get: function () { return memory_data_source_1.createMemoryDataSource; } });
38
+ var scheduler_1 = require("./lib/record/scheduler");
39
+ Object.defineProperty(exports, "hostScheduler", { enumerable: true, get: function () { return scheduler_1.hostScheduler; } });
40
+ Object.defineProperty(exports, "wait", { enumerable: true, get: function () { return scheduler_1.wait; } });
41
+ var form_1 = require("./lib/record/form");
42
+ Object.defineProperty(exports, "createForm", { enumerable: true, get: function () { return form_1.createForm; } });
43
+ var messages_1 = require("./lib/record/messages");
44
+ Object.defineProperty(exports, "MESSAGES", { enumerable: true, get: function () { return messages_1.MESSAGES; } });
45
+ Object.defineProperty(exports, "fill", { enumerable: true, get: function () { return messages_1.fill; } });
46
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/core/src/index.ts"],"names":[],"mappings":";;;AACA,4CAc4B;AAb1B,mGAAA,UAAU,OAAA;AACV,oGAAA,WAAW,OAAA;AACX,oGAAA,WAAW,OAAA;AACX,qGAAA,YAAY,OAAA;AACZ,wGAAA,eAAe,OAAA;AACf,qGAAA,YAAY,OAAA;AACZ,8GAAA,qBAAqB,OAAA;AAQvB,8CAwB6B;AAvB3B,wGAAA,cAAc,OAAA;AACd,0GAAA,gBAAgB,OAAA;AAChB,0GAAA,gBAAgB,OAAA;AAsBlB,0CAAyF;AAAhF,sGAAA,cAAc,OAAA;AAAE,kGAAA,UAAU,OAAA;AACnC,kDAA0F;AAAjF,wGAAA,YAAY,OAAA;AACrB,wDAA0D;AAAjD,6GAAA,cAAc,OAAA;AACvB,sDAAmF;AAA1E,2GAAA,eAAe,OAAA;AACxB,sEAAsF;AAA7E,oHAAA,gBAAgB,OAAA;AAAE,mHAAA,eAAe,OAAA;AAC1C,8CAY6B;AAX3B,oGAAA,UAAU,OAAA;AACV,uGAAA,aAAa,OAAA;AACb,iGAAA,OAAO,OAAA;AACP,2GAAA,iBAAiB,OAAA;AASnB,4CAA6D;AAApD,mGAAA,UAAU,OAAA;AAAE,oGAAA,WAAW,OAAA;AAgBhC,sEAA8H;AAArH,4HAAA,sBAAsB,OAAA;AAC/B,oDAA6E;AAApE,0GAAA,aAAa,OAAA;AAAE,iGAAA,IAAI,OAAA;AAC5B,0CAS2B;AARzB,kGAAA,UAAU,OAAA;AASZ,kDAAmF;AAA1E,oGAAA,QAAQ,OAAA;AAAE,gGAAA,IAAI,OAAA"}
package/src/index.mjs ADDED
@@ -0,0 +1,14 @@
1
+ export { FIELD_NAME, FIELD_TYPES, FieldSchema, FieldsSchema, LineFieldSchema, OptionSchema, FilterConditionSchema, } from './lib/format/field.mjs';
2
+ export { ModifierSchema, LayoutNodeSchema, RootLayoutSchema, } from './lib/format/layout.mjs';
3
+ export { FORMAT_VERSION, PageSchema } from './lib/format/page.mjs';
4
+ export { validatePage } from './lib/format/validate.mjs';
5
+ export { pageJsonSchema } from './lib/format/json-schema.mjs';
6
+ export { compileModifier } from './lib/expression/modifier.mjs';
7
+ export { evaluateModifier, isModifierValid } from './lib/expression/evaluateModifier.mjs';
8
+ export { emptyValue, initialValues, isEmpty, expressionContext, } from './lib/record/values.mjs';
9
+ export { checkValue, formatBytes } from './lib/record/check.mjs';
10
+ export { createMemoryDataSource } from './lib/record/memory-data-source.mjs';
11
+ export { hostScheduler, wait } from './lib/record/scheduler.mjs';
12
+ export { createForm, } from './lib/record/form.mjs';
13
+ export { MESSAGES, fill } from './lib/record/messages.mjs';
14
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","sourceRoot":"","sources":["../../../../libs/core/src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,UAAU,EACV,WAAW,EACX,WAAW,EACX,YAAY,EACZ,eAAe,EACf,YAAY,EACZ,qBAAqB,GAOtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,cAAc,EACd,gBAAgB,EAChB,gBAAgB,GAqBjB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,cAAc,EAAE,UAAU,EAA4B,MAAM,mBAAmB,CAAC;AACzF,OAAO,EAAE,YAAY,EAAuC,MAAM,uBAAuB,CAAC;AAC1F,OAAO,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAyB,MAAM,2BAA2B,CAAC;AACnF,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,mCAAmC,CAAC;AACtF,OAAO,EACL,UAAU,EACV,aAAa,EACb,OAAO,EACP,iBAAiB,GAQlB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAgB7D,OAAO,EAAE,sBAAsB,EAAuD,MAAM,iCAAiC,CAAC;AAC9H,OAAO,EAAE,aAAa,EAAE,IAAI,EAAkB,MAAM,wBAAwB,CAAC;AAC7E,OAAO,EACL,UAAU,GAQX,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,QAAQ,EAAE,IAAI,EAA8B,MAAM,uBAAuB,CAAC"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * evaluateModifier - Evaluate modifier expressions with form context
3
+ *
4
+ * Phase 2 implementation with full expression parser.
5
+ * Supports Python-like expressions used in Flectra modifiers.
6
+ *
7
+ * Structura Reference:
8
+ * - DynBehaviorManager.evaluateCondition() method
9
+ * - Supports Python-like expressions: "state == 'draft' and amount > 100"
10
+ *
11
+ * Supported features:
12
+ * - Comparison operators: ==, !=, <>, <, >, <=, >=
13
+ * - In operators: in, not in
14
+ * - Logical operators: and, or, not
15
+ * - Parentheses for precedence
16
+ * - Nested field access: partner_id.country_id.name
17
+ * - Truthiness checks: partner_id (true if partner_id has value)
18
+ *
19
+ * @param expression - The modifier expression to evaluate
20
+ * @param context - Current form values
21
+ * @returns Boolean result of evaluation
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * // Simple boolean
26
+ * evaluateModifier(true, {}) // => true
27
+ *
28
+ * // String boolean
29
+ * evaluateModifier('1', {}) // => true
30
+ * evaluateModifier('True', {}) // => true
31
+ *
32
+ * // Field truthiness
33
+ * evaluateModifier('is_company', { is_company: true }) // => true
34
+ * evaluateModifier('partner_id', { partner_id: null }) // => false
35
+ *
36
+ * // Comparison expressions
37
+ * evaluateModifier("state == 'done'", { state: 'done' }) // => true
38
+ * evaluateModifier("amount > 100", { amount: 150 }) // => true
39
+ *
40
+ * // Logical expressions
41
+ * evaluateModifier("state == 'draft' and amount > 100", { state: 'draft', amount: 150 }) // => true
42
+ * evaluateModifier("state in ['draft', 'sent']", { state: 'draft' }) // => true
43
+ *
44
+ * // Nested field access
45
+ * evaluateModifier("partner_id.country_id == 5", { partner_id: { country_id: 5 } }) // => true
46
+ * ```
47
+ */
48
+ export declare function evaluateModifier(expression: string | boolean | undefined, context: Record<string, unknown>): boolean;
49
+ /**
50
+ * Check if a modifier expression is valid and can be parsed
51
+ *
52
+ * @param expression - The modifier expression to check
53
+ * @returns true if expression is valid, false otherwise
54
+ */
55
+ export declare function isModifierValid(expression: string | boolean | undefined): boolean;
@@ -0,0 +1,55 @@
1
+ /**
2
+ * evaluateModifier - Evaluate modifier expressions with form context
3
+ *
4
+ * Phase 2 implementation with full expression parser.
5
+ * Supports Python-like expressions used in Flectra modifiers.
6
+ *
7
+ * Structura Reference:
8
+ * - DynBehaviorManager.evaluateCondition() method
9
+ * - Supports Python-like expressions: "state == 'draft' and amount > 100"
10
+ *
11
+ * Supported features:
12
+ * - Comparison operators: ==, !=, <>, <, >, <=, >=
13
+ * - In operators: in, not in
14
+ * - Logical operators: and, or, not
15
+ * - Parentheses for precedence
16
+ * - Nested field access: partner_id.country_id.name
17
+ * - Truthiness checks: partner_id (true if partner_id has value)
18
+ *
19
+ * @param expression - The modifier expression to evaluate
20
+ * @param context - Current form values
21
+ * @returns Boolean result of evaluation
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * // Simple boolean
26
+ * evaluateModifier(true, {}) // => true
27
+ *
28
+ * // String boolean
29
+ * evaluateModifier('1', {}) // => true
30
+ * evaluateModifier('True', {}) // => true
31
+ *
32
+ * // Field truthiness
33
+ * evaluateModifier('is_company', { is_company: true }) // => true
34
+ * evaluateModifier('partner_id', { partner_id: null }) // => false
35
+ *
36
+ * // Comparison expressions
37
+ * evaluateModifier("state == 'done'", { state: 'done' }) // => true
38
+ * evaluateModifier("amount > 100", { amount: 150 }) // => true
39
+ *
40
+ * // Logical expressions
41
+ * evaluateModifier("state == 'draft' and amount > 100", { state: 'draft', amount: 150 }) // => true
42
+ * evaluateModifier("state in ['draft', 'sent']", { state: 'draft' }) // => true
43
+ *
44
+ * // Nested field access
45
+ * evaluateModifier("partner_id.country_id == 5", { partner_id: { country_id: 5 } }) // => true
46
+ * ```
47
+ */
48
+ export declare function evaluateModifier(expression: string | boolean | undefined, context: Record<string, unknown>): boolean;
49
+ /**
50
+ * Check if a modifier expression is valid and can be parsed
51
+ *
52
+ * @param expression - The modifier expression to check
53
+ * @returns true if expression is valid, false otherwise
54
+ */
55
+ export declare function isModifierValid(expression: string | boolean | undefined): boolean;
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ /**
3
+ * evaluateModifier - Evaluate modifier expressions with form context
4
+ *
5
+ * Phase 2 implementation with full expression parser.
6
+ * Supports Python-like expressions used in Flectra modifiers.
7
+ *
8
+ * Structura Reference:
9
+ * - DynBehaviorManager.evaluateCondition() method
10
+ * - Supports Python-like expressions: "state == 'draft' and amount > 100"
11
+ *
12
+ * Supported features:
13
+ * - Comparison operators: ==, !=, <>, <, >, <=, >=
14
+ * - In operators: in, not in
15
+ * - Logical operators: and, or, not
16
+ * - Parentheses for precedence
17
+ * - Nested field access: partner_id.country_id.name
18
+ * - Truthiness checks: partner_id (true if partner_id has value)
19
+ *
20
+ * @param expression - The modifier expression to evaluate
21
+ * @param context - Current form values
22
+ * @returns Boolean result of evaluation
23
+ *
24
+ * @example
25
+ * ```typescript
26
+ * // Simple boolean
27
+ * evaluateModifier(true, {}) // => true
28
+ *
29
+ * // String boolean
30
+ * evaluateModifier('1', {}) // => true
31
+ * evaluateModifier('True', {}) // => true
32
+ *
33
+ * // Field truthiness
34
+ * evaluateModifier('is_company', { is_company: true }) // => true
35
+ * evaluateModifier('partner_id', { partner_id: null }) // => false
36
+ *
37
+ * // Comparison expressions
38
+ * evaluateModifier("state == 'done'", { state: 'done' }) // => true
39
+ * evaluateModifier("amount > 100", { amount: 150 }) // => true
40
+ *
41
+ * // Logical expressions
42
+ * evaluateModifier("state == 'draft' and amount > 100", { state: 'draft', amount: 150 }) // => true
43
+ * evaluateModifier("state in ['draft', 'sent']", { state: 'draft' }) // => true
44
+ *
45
+ * // Nested field access
46
+ * evaluateModifier("partner_id.country_id == 5", { partner_id: { country_id: 5 } }) // => true
47
+ * ```
48
+ */
49
+ Object.defineProperty(exports, "__esModule", { value: true });
50
+ exports.evaluateModifier = evaluateModifier;
51
+ exports.isModifierValid = isModifierValid;
52
+ const tokenizer_1 = require("./tokenizer");
53
+ const parser_1 = require("./parser");
54
+ const evaluator_1 = require("./evaluator");
55
+ function evaluateModifier(expression, context) {
56
+ // Undefined modifier = false (field is not affected)
57
+ if (expression === undefined) {
58
+ return false;
59
+ }
60
+ // Direct boolean value
61
+ if (typeof expression === 'boolean') {
62
+ return expression;
63
+ }
64
+ // String representation of boolean
65
+ if (expression === '1' || expression === 'True' || expression === 'true') {
66
+ return true;
67
+ }
68
+ if (expression === '0' || expression === 'False' || expression === 'false') {
69
+ return false;
70
+ }
71
+ // Empty string = false
72
+ if (expression === '') {
73
+ return false;
74
+ }
75
+ // Parse and evaluate complex expression
76
+ try {
77
+ const tokens = (0, tokenizer_1.tokenize)(expression);
78
+ // Empty token list
79
+ if (tokens.length === 0) {
80
+ return false;
81
+ }
82
+ const parser = new parser_1.ExpressionParser(tokens);
83
+ const ast = parser.parse();
84
+ const result = (0, evaluator_1.evaluate)(ast, context);
85
+ // Convert result to boolean
86
+ return (0, evaluator_1.truthy)(result);
87
+ }
88
+ catch {
89
+ // A page is validated before it runs (validatePage reads every
90
+ // expression), so this only guards pages that skipped validation.
91
+ // Fail safely - return false so field is not hidden/disabled by broken modifier
92
+ return false;
93
+ }
94
+ }
95
+ /**
96
+ * Check if a modifier expression is valid and can be parsed
97
+ *
98
+ * @param expression - The modifier expression to check
99
+ * @returns true if expression is valid, false otherwise
100
+ */
101
+ function isModifierValid(expression) {
102
+ if (expression === undefined || typeof expression === 'boolean') {
103
+ return true;
104
+ }
105
+ if (expression === '') {
106
+ return true;
107
+ }
108
+ try {
109
+ const tokens = (0, tokenizer_1.tokenize)(expression);
110
+ if (tokens.length === 0) {
111
+ return true;
112
+ }
113
+ const parser = new parser_1.ExpressionParser(tokens);
114
+ parser.parse();
115
+ return true;
116
+ }
117
+ catch {
118
+ return false;
119
+ }
120
+ }
121
+ //# sourceMappingURL=evaluateModifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluateModifier.js","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/expression/evaluateModifier.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;;AAMH,4CAiDC;AAQD,0CAoBC;AAjFD,2CAAuC;AACvC,qCAA4C;AAC5C,2CAA+C;AAE/C,SAAgB,gBAAgB,CAC9B,UAAwC,EACxC,OAAgC;IAEhC,qDAAqD;IACrD,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC7B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,uBAAuB;IACvB,IAAI,OAAO,UAAU,KAAK,SAAS,EAAE,CAAC;QACpC,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,mCAAmC;IACnC,IAAI,UAAU,KAAK,GAAG,IAAI,UAAU,KAAK,MAAM,IAAI,UAAU,KAAK,MAAM,EAAE,CAAC;QACzE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,UAAU,KAAK,GAAG,IAAI,UAAU,KAAK,OAAO,IAAI,UAAU,KAAK,OAAO,EAAE,CAAC;QAC3E,OAAO,KAAK,CAAC;IACf,CAAC;IAED,uBAAuB;IACvB,IAAI,UAAU,KAAK,EAAE,EAAE,CAAC;QACtB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,wCAAwC;IACxC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAA,oBAAQ,EAAC,UAAU,CAAC,CAAC;QAEpC,mBAAmB;QACnB,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,yBAAgB,CAAC,MAAM,CAAC,CAAC;QAC5C,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,IAAA,oBAAQ,EAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAEtC,4BAA4B;QAC5B,OAAO,IAAA,kBAAM,EAAC,MAAM,CAAC,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,+DAA+D;QAC/D,kEAAkE;QAClE,gFAAgF;QAChF,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAgB,eAAe,CAAC,UAAwC;IACtE,IAAI,UAAU,KAAK,SAAS,IAAI,OAAO,UAAU,KAAK,SAAS,EAAE,CAAC;QAChE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,UAAU,KAAK,EAAE,EAAE,CAAC;QACtB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAA,oBAAQ,EAAC,UAAU,CAAC,CAAC;QACpC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,yBAAgB,CAAC,MAAM,CAAC,CAAC;QAC5C,MAAM,CAAC,KAAK,EAAE,CAAC;QACf,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
@@ -0,0 +1,117 @@
1
+ /**
2
+ * evaluateModifier - Evaluate modifier expressions with form context
3
+ *
4
+ * Phase 2 implementation with full expression parser.
5
+ * Supports Python-like expressions used in Flectra modifiers.
6
+ *
7
+ * Structura Reference:
8
+ * - DynBehaviorManager.evaluateCondition() method
9
+ * - Supports Python-like expressions: "state == 'draft' and amount > 100"
10
+ *
11
+ * Supported features:
12
+ * - Comparison operators: ==, !=, <>, <, >, <=, >=
13
+ * - In operators: in, not in
14
+ * - Logical operators: and, or, not
15
+ * - Parentheses for precedence
16
+ * - Nested field access: partner_id.country_id.name
17
+ * - Truthiness checks: partner_id (true if partner_id has value)
18
+ *
19
+ * @param expression - The modifier expression to evaluate
20
+ * @param context - Current form values
21
+ * @returns Boolean result of evaluation
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * // Simple boolean
26
+ * evaluateModifier(true, {}) // => true
27
+ *
28
+ * // String boolean
29
+ * evaluateModifier('1', {}) // => true
30
+ * evaluateModifier('True', {}) // => true
31
+ *
32
+ * // Field truthiness
33
+ * evaluateModifier('is_company', { is_company: true }) // => true
34
+ * evaluateModifier('partner_id', { partner_id: null }) // => false
35
+ *
36
+ * // Comparison expressions
37
+ * evaluateModifier("state == 'done'", { state: 'done' }) // => true
38
+ * evaluateModifier("amount > 100", { amount: 150 }) // => true
39
+ *
40
+ * // Logical expressions
41
+ * evaluateModifier("state == 'draft' and amount > 100", { state: 'draft', amount: 150 }) // => true
42
+ * evaluateModifier("state in ['draft', 'sent']", { state: 'draft' }) // => true
43
+ *
44
+ * // Nested field access
45
+ * evaluateModifier("partner_id.country_id == 5", { partner_id: { country_id: 5 } }) // => true
46
+ * ```
47
+ */
48
+ import { tokenize } from './tokenizer.mjs';
49
+ import { ExpressionParser } from './parser.mjs';
50
+ import { evaluate, truthy } from './evaluator.mjs';
51
+ export function evaluateModifier(expression, context) {
52
+ // Undefined modifier = false (field is not affected)
53
+ if (expression === undefined) {
54
+ return false;
55
+ }
56
+ // Direct boolean value
57
+ if (typeof expression === 'boolean') {
58
+ return expression;
59
+ }
60
+ // String representation of boolean
61
+ if (expression === '1' || expression === 'True' || expression === 'true') {
62
+ return true;
63
+ }
64
+ if (expression === '0' || expression === 'False' || expression === 'false') {
65
+ return false;
66
+ }
67
+ // Empty string = false
68
+ if (expression === '') {
69
+ return false;
70
+ }
71
+ // Parse and evaluate complex expression
72
+ try {
73
+ const tokens = tokenize(expression);
74
+ // Empty token list
75
+ if (tokens.length === 0) {
76
+ return false;
77
+ }
78
+ const parser = new ExpressionParser(tokens);
79
+ const ast = parser.parse();
80
+ const result = evaluate(ast, context);
81
+ // Convert result to boolean
82
+ return truthy(result);
83
+ }
84
+ catch {
85
+ // A page is validated before it runs (validatePage reads every
86
+ // expression), so this only guards pages that skipped validation.
87
+ // Fail safely - return false so field is not hidden/disabled by broken modifier
88
+ return false;
89
+ }
90
+ }
91
+ /**
92
+ * Check if a modifier expression is valid and can be parsed
93
+ *
94
+ * @param expression - The modifier expression to check
95
+ * @returns true if expression is valid, false otherwise
96
+ */
97
+ export function isModifierValid(expression) {
98
+ if (expression === undefined || typeof expression === 'boolean') {
99
+ return true;
100
+ }
101
+ if (expression === '') {
102
+ return true;
103
+ }
104
+ try {
105
+ const tokens = tokenize(expression);
106
+ if (tokens.length === 0) {
107
+ return true;
108
+ }
109
+ const parser = new ExpressionParser(tokens);
110
+ parser.parse();
111
+ return true;
112
+ }
113
+ catch {
114
+ return false;
115
+ }
116
+ }
117
+ //# sourceMappingURL=evaluateModifier.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluateModifier.mjs","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/expression/evaluateModifier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8CG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE/C,MAAM,UAAU,gBAAgB,CAC9B,UAAwC,EACxC,OAAgC;IAEhC,qDAAqD;IACrD,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;QAC7B,OAAO,KAAK,CAAC;IACf,CAAC;IAED,uBAAuB;IACvB,IAAI,OAAO,UAAU,KAAK,SAAS,EAAE,CAAC;QACpC,OAAO,UAAU,CAAC;IACpB,CAAC;IAED,mCAAmC;IACnC,IAAI,UAAU,KAAK,GAAG,IAAI,UAAU,KAAK,MAAM,IAAI,UAAU,KAAK,MAAM,EAAE,CAAC;QACzE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,UAAU,KAAK,GAAG,IAAI,UAAU,KAAK,OAAO,IAAI,UAAU,KAAK,OAAO,EAAE,CAAC;QAC3E,OAAO,KAAK,CAAC;IACf,CAAC;IAED,uBAAuB;IACvB,IAAI,UAAU,KAAK,EAAE,EAAE,CAAC;QACtB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,wCAAwC;IACxC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC;QAEpC,mBAAmB;QACnB,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,gBAAgB,CAAC,MAAM,CAAC,CAAC;QAC5C,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAEtC,4BAA4B;QAC5B,OAAO,MAAM,CAAC,MAAM,CAAC,CAAC;IACxB,CAAC;IAAC,MAAM,CAAC;QACP,+DAA+D;QAC/D,kEAAkE;QAClE,gFAAgF;QAChF,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,UAAwC;IACtE,IAAI,UAAU,KAAK,SAAS,IAAI,OAAO,UAAU,KAAK,SAAS,EAAE,CAAC;QAChE,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,UAAU,KAAK,EAAE,EAAE,CAAC;QACtB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,UAAU,CAAC,CAAC;QACpC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,MAAM,MAAM,GAAG,IAAI,gBAAgB,CAAC,MAAM,CAAC,CAAC;QAC5C,MAAM,CAAC,KAAK,EAAE,CAAC;QACf,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * AST evaluator for modifiers, ported from the React form engine.
3
+ *
4
+ * Python semantics where the React version used JavaScript's: an empty list
5
+ * or string is false, and an empty value is never smaller or larger than
6
+ * anything — modifiers come from backends that think in Python.
7
+ */
8
+ import type { ASTNode } from './parser.mjs';
9
+ /**
10
+ * Evaluate an AST node against a context object
11
+ *
12
+ * @param ast - The AST node to evaluate
13
+ * @param context - Object containing field values
14
+ * @returns The result of evaluation
15
+ *
16
+ * @example
17
+ * const ast = { type: 'BinaryOp', operator: '==', left: {...}, right: {...} };
18
+ * const context = { state: 'draft', amount: 100 };
19
+ * evaluate(ast, context); // Returns boolean result
20
+ */
21
+ export declare function evaluate(ast: ASTNode, context: Record<string, unknown>): unknown;
22
+ /** Python's truth test: empty lists, strings and objects, 0 and None are false. */
23
+ export declare function truthy(value: unknown): boolean;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * AST evaluator for modifiers, ported from the React form engine.
3
+ *
4
+ * Python semantics where the React version used JavaScript's: an empty list
5
+ * or string is false, and an empty value is never smaller or larger than
6
+ * anything — modifiers come from backends that think in Python.
7
+ */
8
+ import type { ASTNode } from './parser';
9
+ /**
10
+ * Evaluate an AST node against a context object
11
+ *
12
+ * @param ast - The AST node to evaluate
13
+ * @param context - Object containing field values
14
+ * @returns The result of evaluation
15
+ *
16
+ * @example
17
+ * const ast = { type: 'BinaryOp', operator: '==', left: {...}, right: {...} };
18
+ * const context = { state: 'draft', amount: 100 };
19
+ * evaluate(ast, context); // Returns boolean result
20
+ */
21
+ export declare function evaluate(ast: ASTNode, context: Record<string, unknown>): unknown;
22
+ /** Python's truth test: empty lists, strings and objects, 0 and None are false. */
23
+ export declare function truthy(value: unknown): boolean;
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ /**
3
+ * AST evaluator for modifiers, ported from the React form engine.
4
+ *
5
+ * Python semantics where the React version used JavaScript's: an empty list
6
+ * or string is false, and an empty value is never smaller or larger than
7
+ * anything — modifiers come from backends that think in Python.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.evaluate = evaluate;
11
+ exports.truthy = truthy;
12
+ /**
13
+ * Evaluate an AST node against a context object
14
+ *
15
+ * @param ast - The AST node to evaluate
16
+ * @param context - Object containing field values
17
+ * @returns The result of evaluation
18
+ *
19
+ * @example
20
+ * const ast = { type: 'BinaryOp', operator: '==', left: {...}, right: {...} };
21
+ * const context = { state: 'draft', amount: 100 };
22
+ * evaluate(ast, context); // Returns boolean result
23
+ */
24
+ function evaluate(ast, context) {
25
+ switch (ast.type) {
26
+ case 'BinaryOp':
27
+ return evaluateBinaryOp(ast, context);
28
+ case 'UnaryOp':
29
+ return evaluateUnaryOp(ast, context);
30
+ case 'Literal':
31
+ return ast.value;
32
+ case 'Identifier':
33
+ return getNestedValue(context, ast.name);
34
+ default:
35
+ throw new Error(`Unknown AST node type: ${ast.type}`);
36
+ }
37
+ }
38
+ /**
39
+ * Evaluate binary operations
40
+ */
41
+ function evaluateBinaryOp(node, context) {
42
+ const left = normalize(evaluate(node.left, context));
43
+ const right = normalize(evaluate(node.right, context));
44
+ const operator = node.operator.toLowerCase();
45
+ const ordered = left !== null && right !== null;
46
+ switch (operator) {
47
+ // Comparison operators
48
+ case '==':
49
+ return left === right;
50
+ case '!=':
51
+ case '<>':
52
+ return left !== right;
53
+ case '<':
54
+ return ordered && left < right;
55
+ case '>':
56
+ return ordered && left > right;
57
+ case '<=':
58
+ return ordered && left <= right;
59
+ case '>=':
60
+ return ordered && left >= right;
61
+ // In operators
62
+ case 'in':
63
+ return Array.isArray(right) && right.includes(left);
64
+ case 'not in':
65
+ return Array.isArray(right) && !right.includes(left);
66
+ // Logical operators (use truthiness)
67
+ case 'and':
68
+ return truthy(left) && truthy(right);
69
+ case 'or':
70
+ return truthy(left) || truthy(right);
71
+ default:
72
+ throw new Error(`Unknown binary operator: ${node.operator}`);
73
+ }
74
+ }
75
+ /**
76
+ * Evaluate unary operations
77
+ */
78
+ function evaluateUnaryOp(node, context) {
79
+ const operand = evaluate(node.operand, context);
80
+ const operator = node.operator.toLowerCase();
81
+ switch (operator) {
82
+ case 'not':
83
+ return !truthy(operand);
84
+ default:
85
+ throw new Error(`Unknown unary operator: ${node.operator}`);
86
+ }
87
+ }
88
+ /** A missing value compares like None. */
89
+ function normalize(value) {
90
+ return value === undefined ? null : value;
91
+ }
92
+ /** Python's truth test: empty lists, strings and objects, 0 and None are false. */
93
+ function truthy(value) {
94
+ if (Array.isArray(value))
95
+ return value.length > 0;
96
+ if (value !== null && typeof value === 'object')
97
+ return Object.keys(value).length > 0;
98
+ return Boolean(value);
99
+ }
100
+ /**
101
+ * Get a nested value from an object using dot notation
102
+ *
103
+ * @param obj - The object to traverse
104
+ * @param path - Dot-separated path (e.g., 'partner_id.country_id.name')
105
+ * @returns The value at the path, or undefined if not found
106
+ *
107
+ * @example
108
+ * getNestedValue({ a: { b: { c: 5 } } }, 'a.b.c') // Returns 5
109
+ * getNestedValue({ a: null }, 'a.b.c') // Returns undefined
110
+ */
111
+ function getNestedValue(obj, path) {
112
+ const parts = path.split('.');
113
+ let current = obj;
114
+ for (const part of parts) {
115
+ if (current === null || current === undefined) {
116
+ return undefined;
117
+ }
118
+ current = current[part];
119
+ }
120
+ return current;
121
+ }
122
+ //# sourceMappingURL=evaluator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evaluator.js","sourceRoot":"","sources":["../../../../../../libs/core/src/lib/expression/evaluator.ts"],"names":[],"mappings":"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"}