fable 3.1.32 → 3.1.34

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 (33) hide show
  1. package/dist/fable.js +471 -371
  2. package/dist/fable.js.map +1 -1
  3. package/dist/fable.min.js +2 -2
  4. package/dist/fable.min.js.map +1 -1
  5. package/example_applications/mathematical_playground/README.md +27 -0
  6. package/package.json +2 -2
  7. package/source/Fable.js +0 -1
  8. package/source/services/Fable-Service-CSVParser.js +177 -177
  9. package/source/services/Fable-Service-DataFormat.js +22 -22
  10. package/source/services/Fable-Service-DataGeneration.js +161 -161
  11. package/source/services/Fable-Service-DateManipulation.js +209 -209
  12. package/source/services/Fable-Service-EnvironmentData-Web.js +3 -3
  13. package/source/services/Fable-Service-EnvironmentData.js +3 -3
  14. package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-ExpressionTokenizer-DirectiveMutation.js +136 -0
  15. package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-ExpressionTokenizer.js +6 -0
  16. package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-FunctionMap.json +39 -0
  17. package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-SolvePostfixedExpression.js +2 -2
  18. package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-TokenMap.json +9 -0
  19. package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-ValueMarshal.js +3 -3
  20. package/source/services/Fable-Service-ExpressionParser.js +154 -22
  21. package/source/services/Fable-Service-FilePersistence.js +2 -2
  22. package/source/services/Fable-Service-Logic.js +1 -1
  23. package/source/services/Fable-Service-Math.js +293 -57
  24. package/source/services/Fable-Service-MetaTemplate.js +2 -2
  25. package/source/services/Fable-Service-Operation.js +7 -7
  26. package/source/services/Fable-Service-ProgressTime.js +3 -3
  27. package/source/services/Fable-Service-RestClient.js +2 -2
  28. package/source/services/Fable-Service-Template.js +4 -4
  29. package/source/services/Fable-Service-Utility.js +6 -6
  30. package/test/ExpressionParser_tests.js +67 -0
  31. package/test/Math_test.js +81 -1
  32. package/source/services/Fable-Service-ExpressionParser/RNI_Randy.json +0 -1
  33. package/source/services/Fable-Service-ExpressionParser/RNI_Tool.json +0 -1
@@ -6,225 +6,225 @@ const libFableServiceProviderBase = require('fable-serviceproviderbase');
6
6
  */
7
7
  class DateManipulation extends libFableServiceProviderBase
8
8
  {
9
- constructor(pFable, pOptions, pServiceHash)
10
- {
11
- super(pFable, pOptions, pServiceHash)
9
+ constructor(pFable, pOptions, pServiceHash)
10
+ {
11
+ super(pFable, pOptions, pServiceHash)
12
12
 
13
- this.serviceType = 'Dates';
13
+ this.serviceType = 'Dates';
14
14
 
15
- this.dayJS = require('dayjs');
15
+ this.dayJS = require('dayjs');
16
16
 
17
- // Include the `weekOfYear` plugin
18
- this.plugin_weekOfYear = require('dayjs/plugin/weekOfYear');
19
- this.dayJS.extend(this.plugin_weekOfYear);
20
- // Include the `weekday` plugin
21
- this.plugin_weekday = require('dayjs/plugin/weekday');
22
- this.dayJS.extend(this.plugin_weekday);
23
- // Include the `isoWeek` plugin
24
- this.plugin_isoWeek = require('dayjs/plugin/isoWeek');
25
- this.dayJS.extend(this.plugin_isoWeek);
26
- // Include the `timezone` plugin
27
- this.plugin_timezone = require('dayjs/plugin/timezone');
28
- this.dayJS.extend(this.plugin_timezone);
29
- // Include the `relativetime` plugin
30
- this.plugin_relativetime = require('dayjs/plugin/relativeTime');
31
- this.dayJS.extend(this.plugin_relativetime);
32
- // Include the `utc` plugin
33
- this.plugin_utc = require('dayjs/plugin/utc');
34
- this.dayJS.extend(this.plugin_utc);
35
- // Include the `advancedFormat` plugin
36
- this.plugin_advancedFormat = require('dayjs/plugin/advancedFormat');
37
- this.dayJS.extend(this.plugin_advancedFormat);
17
+ // Include the `weekOfYear` plugin
18
+ this.plugin_weekOfYear = require('dayjs/plugin/weekOfYear');
19
+ this.dayJS.extend(this.plugin_weekOfYear);
20
+ // Include the `weekday` plugin
21
+ this.plugin_weekday = require('dayjs/plugin/weekday');
22
+ this.dayJS.extend(this.plugin_weekday);
23
+ // Include the `isoWeek` plugin
24
+ this.plugin_isoWeek = require('dayjs/plugin/isoWeek');
25
+ this.dayJS.extend(this.plugin_isoWeek);
26
+ // Include the `timezone` plugin
27
+ this.plugin_timezone = require('dayjs/plugin/timezone');
28
+ this.dayJS.extend(this.plugin_timezone);
29
+ // Include the `relativetime` plugin
30
+ this.plugin_relativetime = require('dayjs/plugin/relativeTime');
31
+ this.dayJS.extend(this.plugin_relativetime);
32
+ // Include the `utc` plugin
33
+ this.plugin_utc = require('dayjs/plugin/utc');
34
+ this.dayJS.extend(this.plugin_utc);
35
+ // Include the `advancedFormat` plugin
36
+ this.plugin_advancedFormat = require('dayjs/plugin/advancedFormat');
37
+ this.dayJS.extend(this.plugin_advancedFormat);
38
38
 
39
- // A developer can include locales if they want
40
- // You would do the following:
41
- // const localeDE = require('dayjs/locale/de');
42
- // _Fable.Dates.dayJS.locale('de');
43
- }
39
+ // A developer can include locales if they want
40
+ // You would do the following:
41
+ // const localeDE = require('dayjs/locale/de');
42
+ // _Fable.Dates.dayJS.locale('de');
43
+ }
44
44
 
45
- /**
46
- * Calculates the difference in milliseconds between two dates.
47
- *
48
- * @param {string|Date|number} pDateStart - The start date. Can be a string, Date object, or timestamp.
49
- * @param {string|Date|number} pDateEnd - The end date. Can be a string, Date object, or timestamp. Defaults to the current date if not provided.
50
- * @param {boolean} pRequireEndDate - If true, the end date must be provided; otherwise, it defaults to the current date.
51
- * @returns {number} The difference in milliseconds between the start and end dates. Returns NaN if the start date is invalid.
52
- */
53
- dateMillisecondDifference(pDateStart, pDateEnd, pRequireEndDate = false)
54
- {
55
- if ((pDateStart === undefined) || (pDateStart === null) || (pDateStart === ''))
56
- {
57
- return NaN;
58
- }
59
- if ((pRequireEndDate || (pRequireEndDate == 1) || (pRequireEndDate == '1')) && ((pDateEnd === undefined) || (pDateEnd === null) || (pDateEnd === '')))
60
- {
61
- return NaN;
62
- }
63
- let tmpStartDate = this.dayJS(pDateStart);
64
- let tmpEndDate = this.dayJS(pDateEnd);
65
- return tmpEndDate.diff(tmpStartDate, 'millisecond');
66
- }
45
+ /**
46
+ * Calculates the difference in milliseconds between two dates.
47
+ *
48
+ * @param {string|Date|number} pDateStart - The start date. Can be a string, Date object, or timestamp.
49
+ * @param {string|Date|number} pDateEnd - The end date. Can be a string, Date object, or timestamp. Defaults to the current date if not provided.
50
+ * @param {boolean} pRequireEndDate - If true, the end date must be provided; otherwise, it defaults to the current date.
51
+ * @returns {number} The difference in milliseconds between the start and end dates. Returns NaN if the start date is invalid.
52
+ */
53
+ dateMillisecondDifference(pDateStart, pDateEnd, pRequireEndDate = false)
54
+ {
55
+ if ((pDateStart === undefined) || (pDateStart === null) || (pDateStart === ''))
56
+ {
57
+ return NaN;
58
+ }
59
+ if ((pRequireEndDate || (pRequireEndDate == 1) || (pRequireEndDate == '1')) && ((pDateEnd === undefined) || (pDateEnd === null) || (pDateEnd === '')))
60
+ {
61
+ return NaN;
62
+ }
63
+ let tmpStartDate = this.dayJS(pDateStart);
64
+ let tmpEndDate = this.dayJS(pDateEnd);
65
+ return tmpEndDate.diff(tmpStartDate, 'millisecond');
66
+ }
67
67
 
68
- /**
69
- * Calculates the difference in seconds between two dates.
70
- *
71
- * @param {string|Date|number} pDateStart - The start date. Can be a string, Date object, or timestamp.
72
- * @param {string|Date|number} pDateEnd - The end date. Can be a string, Date object, or timestamp. Defaults to the current date if not provided.
73
- * @param {boolean} pRequireEndDate - If true, the end date must be provided; otherwise, it defaults to the current date.
74
- * @returns {number} The difference in seconds between the start and end dates. Returns NaN if the start date is invalid.
75
- */
76
- dateSecondDifference(pDateStart, pDateEnd, pRequireEndDate = false)
77
- {
78
- if ((pDateStart === undefined) || (pDateStart === null) || (pDateStart === ''))
79
- {
80
- return NaN;
81
- }
82
- if ((pRequireEndDate || (pRequireEndDate == 1) || (pRequireEndDate == '1')) && ((pDateEnd === undefined) || (pDateEnd === null) || (pDateEnd === '')))
83
- {
84
- return NaN;
85
- }
86
- let tmpStartDate = this.dayJS(pDateStart);
87
- let tmpEndDate = this.dayJS(pDateEnd);
88
- return tmpEndDate.diff(tmpStartDate, 'second');
89
- }
68
+ /**
69
+ * Calculates the difference in seconds between two dates.
70
+ *
71
+ * @param {string|Date|number} pDateStart - The start date. Can be a string, Date object, or timestamp.
72
+ * @param {string|Date|number} pDateEnd - The end date. Can be a string, Date object, or timestamp. Defaults to the current date if not provided.
73
+ * @param {boolean} pRequireEndDate - If true, the end date must be provided; otherwise, it defaults to the current date.
74
+ * @returns {number} The difference in seconds between the start and end dates. Returns NaN if the start date is invalid.
75
+ */
76
+ dateSecondDifference(pDateStart, pDateEnd, pRequireEndDate = false)
77
+ {
78
+ if ((pDateStart === undefined) || (pDateStart === null) || (pDateStart === ''))
79
+ {
80
+ return NaN;
81
+ }
82
+ if ((pRequireEndDate || (pRequireEndDate == 1) || (pRequireEndDate == '1')) && ((pDateEnd === undefined) || (pDateEnd === null) || (pDateEnd === '')))
83
+ {
84
+ return NaN;
85
+ }
86
+ let tmpStartDate = this.dayJS(pDateStart);
87
+ let tmpEndDate = this.dayJS(pDateEnd);
88
+ return tmpEndDate.diff(tmpStartDate, 'second');
89
+ }
90
90
 
91
- /**
92
- * Calculates the difference in minutes between two dates.
93
- *
94
- * @param {string|Date|number} pDateStart - The start date. Can be a string, Date object, or timestamp.
95
- * @param {string|Date|number} pDateEnd - The end date. Can be a string, Date object, or timestamp. Defaults to the current date if not provided.
96
- * @param {boolean} pRequireEndDate - If true, the end date must be provided; otherwise, it defaults to the current date.
97
- * @returns {number} The difference in minutes between the start and end dates. Returns NaN if the start date is invalid.
98
- */
99
- dateMinuteDifference(pDateStart, pDateEnd, pRequireEndDate = false)
100
- {
101
- if ((pDateStart === undefined) || (pDateStart === null) || (pDateStart === ''))
102
- {
103
- return NaN;
104
- }
105
- if ((pRequireEndDate || (pRequireEndDate == 1) || (pRequireEndDate == '1')) && ((pDateEnd === undefined) || (pDateEnd === null) || (pDateEnd === '')))
106
- {
107
- return NaN;
108
- }
109
- let tmpStartDate = this.dayJS(pDateStart);
110
- let tmpEndDate = this.dayJS(pDateEnd);
111
- return tmpEndDate.diff(tmpStartDate, 'minute');
112
- }
91
+ /**
92
+ * Calculates the difference in minutes between two dates.
93
+ *
94
+ * @param {string|Date|number} pDateStart - The start date. Can be a string, Date object, or timestamp.
95
+ * @param {string|Date|number} pDateEnd - The end date. Can be a string, Date object, or timestamp. Defaults to the current date if not provided.
96
+ * @param {boolean} pRequireEndDate - If true, the end date must be provided; otherwise, it defaults to the current date.
97
+ * @returns {number} The difference in minutes between the start and end dates. Returns NaN if the start date is invalid.
98
+ */
99
+ dateMinuteDifference(pDateStart, pDateEnd, pRequireEndDate = false)
100
+ {
101
+ if ((pDateStart === undefined) || (pDateStart === null) || (pDateStart === ''))
102
+ {
103
+ return NaN;
104
+ }
105
+ if ((pRequireEndDate || (pRequireEndDate == 1) || (pRequireEndDate == '1')) && ((pDateEnd === undefined) || (pDateEnd === null) || (pDateEnd === '')))
106
+ {
107
+ return NaN;
108
+ }
109
+ let tmpStartDate = this.dayJS(pDateStart);
110
+ let tmpEndDate = this.dayJS(pDateEnd);
111
+ return tmpEndDate.diff(tmpStartDate, 'minute');
112
+ }
113
113
 
114
- /**
115
- * Calculates the difference in hours between two dates.
116
- *
117
- * @param {string|Date|number} pDateStart - The start date. Can be a string, Date object, or timestamp.
118
- * @param {string|Date|number} pDateEnd - The end date. Can be a string, Date object, or timestamp. Defaults to the current date if not provided.
119
- * @param {boolean} pRequireEndDate - If true, the end date must be provided; otherwise, it defaults to the current date.
120
- * @returns {number} The difference in hours between the start and end dates. Returns NaN if the start date is invalid.
121
- */
122
- dateHourDifference(pDateStart, pDateEnd, pRequireEndDate = false)
123
- {
124
- if ((pDateStart === undefined) || (pDateStart === null) || (pDateStart === ''))
125
- {
126
- return NaN;
127
- }
128
- if ((pRequireEndDate || (pRequireEndDate == 1) || (pRequireEndDate == '1')) && ((pDateEnd === undefined) || (pDateEnd === null) || (pDateEnd === '')))
129
- {
130
- return NaN;
131
- }
132
- let tmpStartDate = this.dayJS(pDateStart);
133
- let tmpEndDate = this.dayJS(pDateEnd);
134
- return tmpEndDate.diff(tmpStartDate, 'hour');
135
- }
114
+ /**
115
+ * Calculates the difference in hours between two dates.
116
+ *
117
+ * @param {string|Date|number} pDateStart - The start date. Can be a string, Date object, or timestamp.
118
+ * @param {string|Date|number} pDateEnd - The end date. Can be a string, Date object, or timestamp. Defaults to the current date if not provided.
119
+ * @param {boolean} pRequireEndDate - If true, the end date must be provided; otherwise, it defaults to the current date.
120
+ * @returns {number} The difference in hours between the start and end dates. Returns NaN if the start date is invalid.
121
+ */
122
+ dateHourDifference(pDateStart, pDateEnd, pRequireEndDate = false)
123
+ {
124
+ if ((pDateStart === undefined) || (pDateStart === null) || (pDateStart === ''))
125
+ {
126
+ return NaN;
127
+ }
128
+ if ((pRequireEndDate || (pRequireEndDate == 1) || (pRequireEndDate == '1')) && ((pDateEnd === undefined) || (pDateEnd === null) || (pDateEnd === '')))
129
+ {
130
+ return NaN;
131
+ }
132
+ let tmpStartDate = this.dayJS(pDateStart);
133
+ let tmpEndDate = this.dayJS(pDateEnd);
134
+ return tmpEndDate.diff(tmpStartDate, 'hour');
135
+ }
136
136
 
137
- /**
138
- * Calculates the difference in days between two dates.
139
- *
140
- * @param {string|Date|number} pDateStart - The start date. Can be a string, Date object, or timestamp.
141
- * @param {string|Date|number} pDateEnd - The end date. Can be a string, Date object, or timestamp. Defaults to the current date if not provided.
142
- * @param {boolean} pRequireEndDate - If true, the end date must be provided; otherwise, it defaults to the current date.
143
- * @returns {number} The difference in days between the start and end dates. Returns NaN if the start date is invalid.
144
- */
145
- dateDayDifference(pDateStart, pDateEnd, pRequireEndDate = false)
146
- {
147
- if ((pDateStart === undefined) || (pDateStart === null) || (pDateStart === ''))
148
- {
149
- return NaN;
150
- }
151
- if ((pRequireEndDate || (pRequireEndDate == 1) || (pRequireEndDate == '1')) && ((pDateEnd === undefined) || (pDateEnd === null) || (pDateEnd === '')))
152
- {
153
- return NaN;
154
- }
155
- let tmpStartDate = this.dayJS(pDateStart);
156
- let tmpEndDate = this.dayJS(pDateEnd);
157
- return tmpEndDate.diff(tmpStartDate, 'day');
158
- }
137
+ /**
138
+ * Calculates the difference in days between two dates.
139
+ *
140
+ * @param {string|Date|number} pDateStart - The start date. Can be a string, Date object, or timestamp.
141
+ * @param {string|Date|number} pDateEnd - The end date. Can be a string, Date object, or timestamp. Defaults to the current date if not provided.
142
+ * @param {boolean} pRequireEndDate - If true, the end date must be provided; otherwise, it defaults to the current date.
143
+ * @returns {number} The difference in days between the start and end dates. Returns NaN if the start date is invalid.
144
+ */
145
+ dateDayDifference(pDateStart, pDateEnd, pRequireEndDate = false)
146
+ {
147
+ if ((pDateStart === undefined) || (pDateStart === null) || (pDateStart === ''))
148
+ {
149
+ return NaN;
150
+ }
151
+ if ((pRequireEndDate || (pRequireEndDate == 1) || (pRequireEndDate == '1')) && ((pDateEnd === undefined) || (pDateEnd === null) || (pDateEnd === '')))
152
+ {
153
+ return NaN;
154
+ }
155
+ let tmpStartDate = this.dayJS(pDateStart);
156
+ let tmpEndDate = this.dayJS(pDateEnd);
157
+ return tmpEndDate.diff(tmpStartDate, 'day');
158
+ }
159
159
 
160
- /**
161
- * Calculates the difference in weeks between two dates.
162
- *
163
- * @param {string|Date|number} pDateStart - The start date. Can be a string, Date object, or timestamp.
164
- * @param {string|Date|number} pDateEnd - The end date. Can be a string, Date object, or timestamp. Defaults to the current date if not provided.
165
- * @param {boolean} pRequireEndDate - If true, the end date must be provided; otherwise, it defaults to the current date.
166
- * @returns {number} The difference in weeks between the two dates. Returns NaN if the start date is invalid.
167
- */
168
- dateWeekDifference(pDateStart, pDateEnd, pRequireEndDate = false)
169
- {
170
- if ((pDateStart === undefined) || (pDateStart === null) || (pDateStart === ''))
171
- {
172
- return NaN;
173
- }
174
- if ((pRequireEndDate || (pRequireEndDate == 1) || (pRequireEndDate == '1')) && ((pDateEnd === undefined) || (pDateEnd === null) || (pDateEnd === '')))
175
- {
176
- return NaN;
177
- }
178
- let tmpStartDate = this.dayJS(pDateStart);
179
- let tmpEndDate = this.dayJS(pDateEnd);
180
- return tmpEndDate.diff(tmpStartDate, 'week');
181
- }
160
+ /**
161
+ * Calculates the difference in weeks between two dates.
162
+ *
163
+ * @param {string|Date|number} pDateStart - The start date. Can be a string, Date object, or timestamp.
164
+ * @param {string|Date|number} pDateEnd - The end date. Can be a string, Date object, or timestamp. Defaults to the current date if not provided.
165
+ * @param {boolean} pRequireEndDate - If true, the end date must be provided; otherwise, it defaults to the current date.
166
+ * @returns {number} The difference in weeks between the two dates. Returns NaN if the start date is invalid.
167
+ */
168
+ dateWeekDifference(pDateStart, pDateEnd, pRequireEndDate = false)
169
+ {
170
+ if ((pDateStart === undefined) || (pDateStart === null) || (pDateStart === ''))
171
+ {
172
+ return NaN;
173
+ }
174
+ if ((pRequireEndDate || (pRequireEndDate == 1) || (pRequireEndDate == '1')) && ((pDateEnd === undefined) || (pDateEnd === null) || (pDateEnd === '')))
175
+ {
176
+ return NaN;
177
+ }
178
+ let tmpStartDate = this.dayJS(pDateStart);
179
+ let tmpEndDate = this.dayJS(pDateEnd);
180
+ return tmpEndDate.diff(tmpStartDate, 'week');
181
+ }
182
182
 
183
- /**
184
- * Calculates the difference in months between two dates.
185
- *
186
- * @param {string|Date|number} pDateStart - The start date. Can be a string, Date object, or timestamp.
187
- * @param {string|Date|number} pDateEnd - The end date. Can be a string, Date object, or timestamp. Defaults to the current date if not provided.
188
- * @param {boolean} pRequireEndDate - If true, the end date must be provided; otherwise, it defaults to the current date.
189
- * @returns {number} The difference in months between the two dates. Returns NaN if the start date is invalid.
190
- */
191
- dateMonthDifference(pDateStart, pDateEnd, pRequireEndDate = false)
192
- {
193
- if ((pDateStart === undefined) || (pDateStart === null) || (pDateStart === ''))
194
- {
195
- return NaN;
196
- }
197
- if ((pRequireEndDate || (pRequireEndDate == 1) || (pRequireEndDate == '1')) && ((pDateEnd === undefined) || (pDateEnd === null) || (pDateEnd === '')))
198
- {
199
- return NaN;
200
- }
201
- let tmpStartDate = this.dayJS(pDateStart);
202
- let tmpEndDate = this.dayJS(pDateEnd);
203
- return tmpEndDate.diff(tmpStartDate, 'month');
204
- }
183
+ /**
184
+ * Calculates the difference in months between two dates.
185
+ *
186
+ * @param {string|Date|number} pDateStart - The start date. Can be a string, Date object, or timestamp.
187
+ * @param {string|Date|number} pDateEnd - The end date. Can be a string, Date object, or timestamp. Defaults to the current date if not provided.
188
+ * @param {boolean} pRequireEndDate - If true, the end date must be provided; otherwise, it defaults to the current date.
189
+ * @returns {number} The difference in months between the two dates. Returns NaN if the start date is invalid.
190
+ */
191
+ dateMonthDifference(pDateStart, pDateEnd, pRequireEndDate = false)
192
+ {
193
+ if ((pDateStart === undefined) || (pDateStart === null) || (pDateStart === ''))
194
+ {
195
+ return NaN;
196
+ }
197
+ if ((pRequireEndDate || (pRequireEndDate == 1) || (pRequireEndDate == '1')) && ((pDateEnd === undefined) || (pDateEnd === null) || (pDateEnd === '')))
198
+ {
199
+ return NaN;
200
+ }
201
+ let tmpStartDate = this.dayJS(pDateStart);
202
+ let tmpEndDate = this.dayJS(pDateEnd);
203
+ return tmpEndDate.diff(tmpStartDate, 'month');
204
+ }
205
205
 
206
- /**
207
- * Calculates the difference in years between two dates.
208
- *
209
- * @param {string|Date|number} pDateStart - The start date. Can be a string, Date object, or timestamp.
210
- * @param {string|Date|number} pDateEnd - The end date. Can be a string, Date object, or timestamp. Defaults to the current date if not provided.
211
- * @param {boolean} pRequireEndDate - If true, the end date must be provided; otherwise, it defaults to the current date.
212
- * @returns {number} The difference in years between the two dates. Returns NaN if the start date is invalid.
213
- */
214
- dateYearDifference(pDateStart, pDateEnd, pRequireEndDate = false)
215
- {
216
- if ((pDateStart === undefined) || (pDateStart === null) || (pDateStart === ''))
217
- {
218
- return NaN;
219
- }
220
- if ((pRequireEndDate || (pRequireEndDate == 1) || (pRequireEndDate == '1')) && ((pDateEnd === undefined) || (pDateEnd === null) || (pDateEnd === '')))
221
- {
222
- return NaN;
223
- }
224
- let tmpStartDate = this.dayJS(pDateStart);
225
- let tmpEndDate = this.dayJS(pDateEnd);
226
- return tmpEndDate.diff(tmpStartDate, 'year');
227
- }
206
+ /**
207
+ * Calculates the difference in years between two dates.
208
+ *
209
+ * @param {string|Date|number} pDateStart - The start date. Can be a string, Date object, or timestamp.
210
+ * @param {string|Date|number} pDateEnd - The end date. Can be a string, Date object, or timestamp. Defaults to the current date if not provided.
211
+ * @param {boolean} pRequireEndDate - If true, the end date must be provided; otherwise, it defaults to the current date.
212
+ * @returns {number} The difference in years between the two dates. Returns NaN if the start date is invalid.
213
+ */
214
+ dateYearDifference(pDateStart, pDateEnd, pRequireEndDate = false)
215
+ {
216
+ if ((pDateStart === undefined) || (pDateStart === null) || (pDateStart === ''))
217
+ {
218
+ return NaN;
219
+ }
220
+ if ((pRequireEndDate || (pRequireEndDate == 1) || (pRequireEndDate == '1')) && ((pDateEnd === undefined) || (pDateEnd === null) || (pDateEnd === '')))
221
+ {
222
+ return NaN;
223
+ }
224
+ let tmpStartDate = this.dayJS(pDateStart);
225
+ let tmpEndDate = this.dayJS(pDateEnd);
226
+ return tmpEndDate.diff(tmpStartDate, 'year');
227
+ }
228
228
 
229
229
  dateAddMilliseconds(pDate, pAmount)
230
230
  {
@@ -255,7 +255,7 @@ class DateManipulation extends libFableServiceProviderBase
255
255
  {
256
256
  return this.dateMath(pDate, pAmount, 'week', 'add');
257
257
  }
258
-
258
+
259
259
  dateAddMonths(pDate, pAmount)
260
260
  {
261
261
  return this.dateMath(pDate, pAmount, 'month', 'add');
@@ -302,4 +302,4 @@ class DateManipulation extends libFableServiceProviderBase
302
302
  }
303
303
  }
304
304
 
305
- module.exports = DateManipulation;
305
+ module.exports = DateManipulation;
@@ -4,12 +4,12 @@ class FableServiceEnvironmentData extends libFableServiceBase
4
4
  {
5
5
  constructor(pFable, pOptions, pServiceHash)
6
6
  {
7
- super(pFable, pOptions, pServiceHash);
7
+ super(pFable, pOptions, pServiceHash);
8
8
 
9
- this.serviceType = 'EnvironmentData';
9
+ this.serviceType = 'EnvironmentData';
10
10
 
11
11
  this.Environment = `web`;
12
12
  }
13
13
  }
14
14
 
15
- module.exports = FableServiceEnvironmentData;
15
+ module.exports = FableServiceEnvironmentData;
@@ -4,12 +4,12 @@ class FableServiceEnvironmentData extends libFableServiceBase
4
4
  {
5
5
  constructor(pFable, pOptions, pServiceHash)
6
6
  {
7
- super(pFable, pOptions, pServiceHash);
7
+ super(pFable, pOptions, pServiceHash);
8
8
 
9
- this.serviceType = 'EnvironmentData';
9
+ this.serviceType = 'EnvironmentData';
10
10
 
11
11
  this.Environment = `node.js`;
12
12
  }
13
13
  }
14
14
 
15
- module.exports = FableServiceEnvironmentData;
15
+ module.exports = FableServiceEnvironmentData;
@@ -0,0 +1,136 @@
1
+ const libExpressionParserOperationBase = require('./Fable-Service-ExpressionParser-Base.js');
2
+
3
+ class ExpressionTokenizerDirectiveMutation extends libExpressionParserOperationBase
4
+ {
5
+ constructor(pFable, pOptions, pServiceHash)
6
+ {
7
+ super(pFable, pOptions, pServiceHash);
8
+ this.serviceType = 'ExpressionParser-TokenizerDirectiveMutation';
9
+
10
+ this.directiveTypes = (
11
+ {
12
+ 'SOLVE': { Name: 'Solve Expression', Code: 'SOLVE' },
13
+ 'SERIES': { Name: 'Series', Code: 'SERIES', From: null, To: null, Step: null },
14
+ 'MONTECARLO': { Name: 'Monte Carlo Simulation', Code: 'MONTECARLO', Iterations: null, Values: {} }
15
+ });
16
+
17
+ this.defaultDirective = this.directiveTypes.SOLVE;
18
+ }
19
+
20
+ parseSeriesDirective(pTokens)
21
+ {
22
+ // This isn't a fancy real parse it's just taking words and stealing values after them.
23
+ let tmpNewSeriesDirectiveDescription = Object.assign({}, this.directiveTypes.SERIES);
24
+
25
+ for (let i = 0; i < pTokens.length; i++)
26
+ {
27
+ let tmpToken = pTokens[i].toUpperCase();
28
+ switch(tmpToken)
29
+ {
30
+ case 'FROM':
31
+ if ((i + 1) < pTokens.length)
32
+ {
33
+ tmpNewSeriesDirectiveDescription.From = pTokens[i + 1];
34
+ }
35
+ break;
36
+
37
+ case 'TO':
38
+ if ((i + 1) < pTokens.length)
39
+ {
40
+ tmpNewSeriesDirectiveDescription.To = pTokens[i + 1];
41
+ }
42
+ break;
43
+
44
+ case 'STEP':
45
+ if ((i + 1) < pTokens.length)
46
+ {
47
+ tmpNewSeriesDirectiveDescription.Step = pTokens[i + 1];
48
+ }
49
+ break;
50
+
51
+ default:
52
+ // Ignore other tokens
53
+ break;
54
+ }
55
+ }
56
+
57
+ return tmpNewSeriesDirectiveDescription;
58
+ }
59
+
60
+ parseDirectives(pResultObject)
61
+ {
62
+ let tmpResults = (typeof(pResultObject) === 'object') ? pResultObject : { ExpressionParserLog: [] };
63
+
64
+ tmpResults.SolverDirectives = this.defaultDirective;
65
+ tmpResults.SolverDirectiveTokens = [];
66
+
67
+ if (tmpResults.RawTokens.length < 2)
68
+ {
69
+ tmpResults.ExpressionParserLog.push(`ExpressionParser.tokenizeDirectiveMutation postprocessor received insufficient tokens to process directives.`);
70
+ this.log.warn(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);
71
+ return tmpResults.SolverDirectives;
72
+ }
73
+
74
+ // Enumerate each of the tmpResults.RawTokens to see if one of the values in the directiveTypeMap exists and is either at the beginning or after the assignment (= or ?=) operator
75
+ for (let i = 0; i < tmpResults.RawTokens.length; i++)
76
+ {
77
+ let tmpToken = tmpResults.RawTokens[i].toUpperCase();
78
+ if (tmpToken in this.directiveTypes)
79
+ {
80
+ // Check if it's at the beginning or after an assignment operator
81
+ // FIXME: This is hard coded assignment operators which is bad juju
82
+ if ((i === 0) || (tmpResults.RawTokens[i-1] === '=') || (tmpResults.RawTokens[i-1] === '?='))
83
+ {
84
+ // We have a directive!
85
+ tmpResults.SolverDirectives.Type = this.directiveTypes[tmpToken];
86
+
87
+ tmpResults.ExpressionParserLog.push(`ExpressionParser.tokenizeDirectiveMutation identified solver directive: ${tmpToken}`);
88
+ this.log.info(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);
89
+
90
+ // Extract the Directive name and everything else from it up until the : token
91
+ let tmpDirectiveTokenStartIndex = i;
92
+ let tmpDirectiveTokenEndIndex = -1;
93
+ for (let j = tmpDirectiveTokenStartIndex + 1; j < tmpResults.RawTokens.length; j++)
94
+ {
95
+ if (tmpResults.RawTokens[j] === ':')
96
+ {
97
+ tmpDirectiveTokenEndIndex = j;
98
+ break;
99
+ }
100
+ }
101
+
102
+ // If the directive token end is not in the expression we don't know what to do
103
+ if (tmpDirectiveTokenEndIndex === -1)
104
+ {
105
+ tmpResults.ExpressionParserLog.push(`ExpressionParser.tokenizeDirectiveMutation could not find the end of the directive token set for directive: ${tmpToken}`);
106
+ this.log.warn(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);
107
+ continue;
108
+ }
109
+
110
+ // Set the tmpResults.SolverDirectiveTokens to the slice of tokens that represent the directive
111
+ tmpResults.SolverDirectiveTokens = tmpResults.RawTokens.slice(tmpDirectiveTokenStartIndex, tmpDirectiveTokenEndIndex);
112
+
113
+ // Remove the directive tokens and the assignment to the left of it from the array of raw tokens
114
+ // the colonoscopy if you will
115
+ tmpResults.RawTokens.splice(0, tmpDirectiveTokenEndIndex + 1);
116
+
117
+ // Further parsing based on directive type could go here
118
+ // e.g. parseSeriesDirective for SERIES, etc.
119
+ switch(tmpToken)
120
+ {
121
+ case 'SERIES':
122
+ tmpResults.SolverDirectives = this.parseSeriesDirective(tmpResults.SolverDirectiveTokens);
123
+ break;
124
+ default:
125
+ // No further parsing needed
126
+ break;
127
+ }
128
+ }
129
+ }
130
+ }
131
+
132
+ return tmpResults.SolverDirectives;
133
+ }
134
+ }
135
+
136
+ module.exports = ExpressionTokenizerDirectiveMutation;
@@ -13,6 +13,7 @@ class ExpressionTokenizer extends libExpressionParserOperationBase
13
13
  let tmpResults = (typeof(pResultObject) === 'object') ? pResultObject : { ExpressionParserLog: [] };
14
14
 
15
15
  tmpResults.RawExpression = pExpression;
16
+ tmpResults.SolverDirectives = {};
16
17
  tmpResults.RawTokens = [];
17
18
  tmpResults.ExpressionParserLog = [];
18
19
 
@@ -203,6 +204,11 @@ class ExpressionTokenizer extends libExpressionParserOperationBase
203
204
  tmpResults.RawTokens.push(tmpCurrentToken);
204
205
  }
205
206
 
207
+ tmpResults.OriginalRawTokens = Array.from(tmpResults.RawTokens);
208
+
209
+ // Potentially mutate the tokens based on directives in the tokenized expression
210
+ this.TokenizerDirectiveMutation.parseDirectives(tmpResults);
211
+
206
212
  return tmpResults.RawTokens;
207
213
  }
208
214
  }