@pbkware/fielded-text-web 0.1.0 → 0.2.1

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 (202) hide show
  1. package/README.md +68 -0
  2. package/dist/api/ft-reader.js +1 -1
  3. package/dist/api/ft-reader.js.map +1 -1
  4. package/dist/api/ft-serialization.js +4 -4
  5. package/dist/api/ft-serialization.js.map +1 -1
  6. package/dist/factory/ft-field-factory.js +1 -1
  7. package/dist/factory/ft-field-factory.js.map +1 -1
  8. package/dist/factory/ft-sequence-redirect-factory.js +3 -3
  9. package/dist/factory/ft-sequence-redirect-factory.js.map +1 -1
  10. package/dist/fields/definitions/ft-boolean-field-definition.js +1 -1
  11. package/dist/fields/definitions/ft-boolean-field-definition.js.map +1 -1
  12. package/dist/fields/definitions/ft-date-time-field-definition.js +1 -1
  13. package/dist/fields/definitions/ft-date-time-field-definition.js.map +1 -1
  14. package/dist/fields/definitions/ft-decimal-field-definition.js +1 -1
  15. package/dist/fields/definitions/ft-decimal-field-definition.js.map +1 -1
  16. package/dist/fields/definitions/ft-field-definition.js +1 -1
  17. package/dist/fields/definitions/ft-field-definition.js.map +1 -1
  18. package/dist/fields/definitions/ft-float-field-definition.js +1 -1
  19. package/dist/fields/definitions/ft-float-field-definition.js.map +1 -1
  20. package/dist/fields/definitions/ft-integer-field-definition.js +1 -1
  21. package/dist/fields/definitions/ft-integer-field-definition.js.map +1 -1
  22. package/dist/fields/definitions/ft-string-field-definition.js +1 -1
  23. package/dist/fields/definitions/ft-string-field-definition.js.map +1 -1
  24. package/dist/fields/instances/errors/ft-field-null-error.js +11 -0
  25. package/dist/fields/instances/errors/ft-field-null-error.js.map +1 -0
  26. package/dist/fields/instances/errors/ft-field-type-error.js +11 -0
  27. package/dist/fields/instances/errors/ft-field-type-error.js.map +1 -0
  28. package/dist/fields/instances/ft-boolean-field.js +14 -6
  29. package/dist/fields/instances/ft-boolean-field.js.map +1 -1
  30. package/dist/fields/instances/ft-date-time-field.js +26 -8
  31. package/dist/fields/instances/ft-date-time-field.js.map +1 -1
  32. package/dist/fields/instances/ft-decimal-field.js +14 -6
  33. package/dist/fields/instances/ft-decimal-field.js.map +1 -1
  34. package/dist/fields/instances/ft-field.js +315 -123
  35. package/dist/fields/instances/ft-field.js.map +1 -1
  36. package/dist/fields/instances/ft-float-field.js +14 -6
  37. package/dist/fields/instances/ft-float-field.js.map +1 -1
  38. package/dist/fields/instances/ft-generic-field.js +29 -67
  39. package/dist/fields/instances/ft-generic-field.js.map +1 -1
  40. package/dist/fields/instances/ft-integer-field.js +24 -8
  41. package/dist/fields/instances/ft-integer-field.js.map +1 -1
  42. package/dist/fields/instances/ft-string-field.js +13 -13
  43. package/dist/fields/instances/ft-string-field.js.map +1 -1
  44. package/dist/index.d.ts +616 -288
  45. package/dist/index.js +12 -3
  46. package/dist/index.js.map +1 -1
  47. package/dist/meta/sequences/core/ft-meta-sequence-list.js +4 -2
  48. package/dist/meta/sequences/core/ft-meta-sequence-list.js.map +1 -1
  49. package/dist/meta/sequences/redirects/ft-meta-sequence-redirect-list.js +1 -1
  50. package/dist/meta/sequences/redirects/ft-meta-sequence-redirect-list.js.map +1 -1
  51. package/dist/meta-serialization/format/ft-xml-meta-serialization.js +4 -6
  52. package/dist/meta-serialization/format/ft-xml-meta-serialization.js.map +1 -1
  53. package/dist/meta-serialization/styles/ft-number-styles-meta-serialization.js +1 -1
  54. package/dist/meta-serialization/styles/ft-number-styles-meta-serialization.js.map +1 -1
  55. package/dist/meta-serialization/types/date-time-meta-serialization.js +1 -1
  56. package/dist/meta-serialization/types/date-time-meta-serialization.js.map +1 -1
  57. package/dist/meta-serialization/types/enums/sequence-redirect-type-meta-serialisation.js +1 -1
  58. package/dist/meta-serialization/types/enums/sequence-redirect-type-meta-serialisation.js.map +1 -1
  59. package/dist/meta-serialization/types/float-meta-serialization.js +2 -2
  60. package/dist/meta-serialization/types/float-meta-serialization.js.map +1 -1
  61. package/dist/meta-serialization/types/integer-float-meta-serialization.js +2 -2
  62. package/dist/meta-serialization/types/integer-float-meta-serialization.js.map +1 -1
  63. package/dist/meta-serialization/utils/implicit-explicit-index-sorter.js +4 -10
  64. package/dist/meta-serialization/utils/implicit-explicit-index-sorter.js.map +1 -1
  65. package/dist/meta-serialization/utils/meta-serialization-sequence-name-resolver.js +25 -2
  66. package/dist/meta-serialization/utils/meta-serialization-sequence-name-resolver.js.map +1 -1
  67. package/dist/meta-serialization/utils/sequence-item-field-indices.js +2 -2
  68. package/dist/meta-serialization/utils/sequence-item-field-indices.js.map +1 -1
  69. package/dist/sequences/redirects/ft-case-insensitive-string-sequence-redirect.js +3 -1
  70. package/dist/sequences/redirects/ft-case-insensitive-string-sequence-redirect.js.map +1 -1
  71. package/dist/serialization/char-reader.js +2 -2
  72. package/dist/serialization/char-reader.js.map +1 -1
  73. package/dist/serialization/declaration-parser.js +1 -1
  74. package/dist/serialization/declaration-parser.js.map +1 -1
  75. package/dist/serialization/delimited-field-parser.js.map +1 -1
  76. package/dist/serialization/events/ft-field-heading-ready-event-args.js.map +1 -0
  77. package/dist/serialization/events/ft-field-value-ready-event-args.js.map +1 -0
  78. package/dist/serialization/events/ft-heading-line-finished-event-args.js.map +1 -0
  79. package/dist/serialization/events/ft-heading-line-started-event-args.js.map +1 -0
  80. package/dist/serialization/events/ft-record-finished-event-args.js.map +1 -0
  81. package/dist/serialization/events/ft-record-started-event-args.js.map +1 -0
  82. package/dist/serialization/events/ft-sequence-redirected-event-args.js.map +1 -0
  83. package/dist/serialization/fixed-width-field-parser.js +1 -1
  84. package/dist/serialization/fixed-width-field-parser.js.map +1 -1
  85. package/dist/serialization/ft-declared-parameters.js +9 -8
  86. package/dist/serialization/ft-declared-parameters.js.map +1 -1
  87. package/dist/serialization/{serialization-core.js → ft-serialization-core.js} +114 -11
  88. package/dist/serialization/ft-serialization-core.js.map +1 -0
  89. package/dist/{types/errors/ft-serialization-error.js → serialization/ft-serialization-error-code.js} +2 -2
  90. package/dist/serialization/ft-serialization-error-code.js.map +1 -0
  91. package/dist/{types/errors/ft-serialization-exception.js → serialization/ft-serialization-error.js} +7 -7
  92. package/dist/serialization/ft-serialization-error.js.map +1 -0
  93. package/dist/serialization/ft-serialization-reader.js +19 -47
  94. package/dist/serialization/ft-serialization-reader.js.map +1 -1
  95. package/dist/serialization/ft-serialization-writer.js +86 -49
  96. package/dist/serialization/ft-serialization-writer.js.map +1 -1
  97. package/dist/serialization/heading-line-record-parser.js +7 -7
  98. package/dist/serialization/heading-line-record-parser.js.map +1 -1
  99. package/dist/serialization/line-parser.js +1 -1
  100. package/dist/serialization/line-parser.js.map +1 -1
  101. package/dist/serialization/{ft-text-reader.js → text-reader/ft-string-reader.js} +1 -13
  102. package/dist/serialization/text-reader/ft-string-reader.js.map +1 -0
  103. package/dist/serialization/text-reader/ft-text-reader.js +13 -0
  104. package/dist/serialization/text-reader/ft-text-reader.js.map +1 -0
  105. package/dist/tsdoc-metadata.json +1 -1
  106. package/dist/types/enums/ft-heading-constraint.js +5 -0
  107. package/dist/types/enums/ft-heading-constraint.js.map +1 -1
  108. package/dist/utils/ft-comma-text.js +247 -0
  109. package/dist/utils/ft-comma-text.js.map +1 -0
  110. package/dist/utils/ft-internal-error.js +129 -0
  111. package/dist/utils/ft-internal-error.js.map +1 -0
  112. package/dist/utils/ft-result.js +2 -0
  113. package/dist/utils/ft-result.js.map +1 -0
  114. package/dist/utils/number-parse.js +33 -0
  115. package/dist/utils/number-parse.js.map +1 -0
  116. package/dist/utils/string-builder.js +40 -0
  117. package/dist/utils/string-builder.js.map +1 -0
  118. package/package.json +27 -25
  119. package/src/api/ft-reader.ts +2 -1
  120. package/src/api/ft-serialization.ts +13 -13
  121. package/src/factory/ft-field-factory.ts +1 -1
  122. package/src/factory/ft-sequence-redirect-factory.ts +4 -4
  123. package/src/fields/definitions/ft-boolean-field-definition.ts +1 -1
  124. package/src/fields/definitions/ft-date-time-field-definition.ts +1 -1
  125. package/src/fields/definitions/ft-decimal-field-definition.ts +1 -1
  126. package/src/fields/definitions/ft-field-definition.ts +1 -1
  127. package/src/fields/definitions/ft-float-field-definition.ts +1 -1
  128. package/src/fields/definitions/ft-generic-field-definition.ts +1 -1
  129. package/src/fields/definitions/ft-integer-field-definition.ts +1 -1
  130. package/src/fields/definitions/ft-string-field-definition.ts +1 -1
  131. package/src/fields/instances/errors/ft-field-null-error.ts +10 -0
  132. package/src/fields/instances/errors/ft-field-type-error.ts +10 -0
  133. package/src/fields/instances/ft-boolean-field.ts +17 -6
  134. package/src/fields/instances/ft-date-time-field.ts +28 -7
  135. package/src/fields/instances/ft-decimal-field.ts +17 -6
  136. package/src/fields/instances/ft-field.ts +329 -145
  137. package/src/fields/instances/ft-float-field.ts +17 -6
  138. package/src/fields/instances/ft-generic-field.ts +32 -88
  139. package/src/fields/instances/ft-integer-field.ts +29 -7
  140. package/src/fields/instances/ft-string-field.ts +15 -12
  141. package/src/index.ts +21 -12
  142. package/src/meta/sequences/core/ft-meta-sequence-list.ts +4 -3
  143. package/src/meta/sequences/redirects/ft-meta-sequence-redirect-list.ts +1 -1
  144. package/src/meta-serialization/format/ft-xml-meta-serialization.ts +4 -7
  145. package/src/meta-serialization/styles/ft-number-styles-meta-serialization.ts +1 -1
  146. package/src/meta-serialization/types/date-time-meta-serialization.ts +1 -1
  147. package/src/meta-serialization/types/enums/meta-element-type-meta-serialization.ts +4 -4
  148. package/src/meta-serialization/types/enums/sequence-redirect-type-meta-serialisation.ts +1 -1
  149. package/src/meta-serialization/types/float-meta-serialization.ts +2 -2
  150. package/src/meta-serialization/types/integer-float-meta-serialization.ts +2 -2
  151. package/src/meta-serialization/utils/implicit-explicit-index-sorter.ts +18 -12
  152. package/src/meta-serialization/utils/meta-serialization-sequence-name-resolver.ts +25 -2
  153. package/src/meta-serialization/utils/sequence-item-field-indices.ts +2 -2
  154. package/src/sequences/redirects/ft-case-insensitive-string-sequence-redirect.ts +3 -1
  155. package/src/serialization/char-reader.ts +2 -2
  156. package/src/serialization/declaration-parser.ts +1 -1
  157. package/src/serialization/delimited-field-parser.ts +3 -3
  158. package/src/serialization/fixed-width-field-parser.ts +4 -4
  159. package/src/serialization/ft-declared-parameters.ts +12 -11
  160. package/src/serialization/{serialization-core.ts → ft-serialization-core.ts} +133 -17
  161. package/src/{types/errors/ft-serialization-error.ts → serialization/ft-serialization-error-code.ts} +2 -2
  162. package/src/{types/errors/ft-serialization-exception.ts → serialization/ft-serialization-error.ts} +14 -9
  163. package/src/serialization/ft-serialization-reader.ts +21 -54
  164. package/src/serialization/ft-serialization-writer.ts +97 -64
  165. package/src/serialization/heading-line-record-parser.ts +10 -10
  166. package/src/serialization/line-parser.ts +1 -1
  167. package/src/serialization/{ft-text-reader.ts → text-reader/ft-string-reader.ts} +1 -24
  168. package/src/serialization/text-reader/ft-text-reader.ts +24 -0
  169. package/src/types/enums/ft-heading-constraint.ts +5 -0
  170. package/src/utils/ft-comma-text.ts +285 -0
  171. package/src/utils/ft-internal-error.ts +143 -0
  172. package/src/utils/ft-result.ts +1 -0
  173. package/src/utils/number-parse.ts +35 -0
  174. package/src/utils/string-builder.ts +47 -0
  175. package/dist/serialization/ft-text-reader.js.map +0 -1
  176. package/dist/serialization/serialization-core.js.map +0 -1
  177. package/dist/types/errors/ft-internal-error.js +0 -14
  178. package/dist/types/errors/ft-internal-error.js.map +0 -1
  179. package/dist/types/errors/ft-serialization-error.js.map +0 -1
  180. package/dist/types/errors/ft-serialization-exception.js.map +0 -1
  181. package/dist/types/events/ft-field-heading-ready-event-args.js.map +0 -1
  182. package/dist/types/events/ft-field-value-ready-event-args.js.map +0 -1
  183. package/dist/types/events/ft-heading-line-finished-event-args.js.map +0 -1
  184. package/dist/types/events/ft-heading-line-started-event-args.js.map +0 -1
  185. package/dist/types/events/ft-record-finished-event-args.js.map +0 -1
  186. package/dist/types/events/ft-record-started-event-args.js.map +0 -1
  187. package/dist/types/events/ft-sequence-redirected-event-args.js.map +0 -1
  188. package/src/types/errors/ft-internal-error.ts +0 -15
  189. /package/dist/{types → serialization}/events/ft-field-heading-ready-event-args.js +0 -0
  190. /package/dist/{types → serialization}/events/ft-field-value-ready-event-args.js +0 -0
  191. /package/dist/{types → serialization}/events/ft-heading-line-finished-event-args.js +0 -0
  192. /package/dist/{types → serialization}/events/ft-heading-line-started-event-args.js +0 -0
  193. /package/dist/{types → serialization}/events/ft-record-finished-event-args.js +0 -0
  194. /package/dist/{types → serialization}/events/ft-record-started-event-args.js +0 -0
  195. /package/dist/{types → serialization}/events/ft-sequence-redirected-event-args.js +0 -0
  196. /package/src/{types → serialization}/events/ft-field-heading-ready-event-args.ts +0 -0
  197. /package/src/{types → serialization}/events/ft-field-value-ready-event-args.ts +0 -0
  198. /package/src/{types → serialization}/events/ft-heading-line-finished-event-args.ts +0 -0
  199. /package/src/{types → serialization}/events/ft-heading-line-started-event-args.ts +0 -0
  200. /package/src/{types → serialization}/events/ft-record-finished-event-args.ts +0 -0
  201. /package/src/{types → serialization}/events/ft-record-started-event-args.ts +0 -0
  202. /package/src/{types → serialization}/events/ft-sequence-redirected-event-args.ts +0 -0
@@ -1,6 +1,9 @@
1
1
  import { FtSequenceInvokation } from '../../sequences/core/ft-sequence-invokation.js';
2
2
  import { FtSequenceItem } from '../../sequences/core/ft-sequence-item.js';
3
+ import { FtDataType } from '../../types/enums/ft-data-type.js';
3
4
  import { FtFloatFieldDefinition } from '../definitions/ft-float-field-definition.js';
5
+ import { FtFieldTypeError } from './errors/ft-field-type-error.js';
6
+ import { FtField } from './ft-field.js';
4
7
  import { FtGenericField } from './ft-generic-field.js';
5
8
 
6
9
  /**
@@ -26,18 +29,26 @@ export class FtFloatField extends FtGenericField<number> {
26
29
  return this.definition.styles;
27
30
  }
28
31
 
29
- get nullableValue(): number | null {
30
- return this.isNull() ? null : this.value;
32
+ static cast(field: FtField): field is FtFloatField {
33
+ return field.dataType === FtDataType.Float;
31
34
  }
32
35
 
33
- set nullableValue(value: number | null) {
34
- if (value === null) {
35
- this.setNull();
36
+ override setValue(newValue: FtField.Value): number {
37
+ if (typeof newValue === 'number') {
38
+ return super.setValue(newValue);
36
39
  } else {
37
- this.value = value;
40
+ throw new FtFieldTypeError(`Invalid type (${typeof newValue}) for float field: ${this.name}`);
38
41
  }
39
42
  }
40
43
 
44
+ protected override getAsFloat(): number {
45
+ return this.getValue();
46
+ }
47
+
48
+ protected override setAsFloat(newValue: number): void {
49
+ super.setValue(newValue);
50
+ }
51
+
41
52
  protected isValueEqual(left: number, right: number): boolean {
42
53
  return left === right;
43
54
  }
@@ -1,6 +1,7 @@
1
1
  import { FtSequenceInvokation } from '../../sequences/core/ft-sequence-invokation.js';
2
2
  import { FtSequenceItem } from '../../sequences/core/ft-sequence-item.js';
3
3
  import { FtSequenceRedirectType } from '../../types/enums/ft-sequence-redirect-type.js';
4
+ import { FtAssertError } from '../../utils/ft-internal-error.js';
4
5
  import { FtGenericFieldDefinition } from '../definitions/ft-generic-field-definition.js';
5
6
  import { FtField } from './ft-field.js';
6
7
 
@@ -9,7 +10,7 @@ import { FtField } from './ft-field.js';
9
10
  * Provides type-safe value access and implements conversion methods.
10
11
  * @public
11
12
  */
12
- export abstract class FtGenericField<T> extends FtField {
13
+ export abstract class FtGenericField<T extends FtField.Value> extends FtField {
13
14
  private _value!: T;
14
15
 
15
16
  protected constructor(
@@ -22,11 +23,11 @@ export abstract class FtGenericField<T> extends FtField {
22
23
 
23
24
  // Verify the sequenceItem's definition matches the provided definition
24
25
  if (sequenceItem.fieldDefinition !== definition) {
25
- throw new Error('SequenceItem definition must match provided definition');
26
- }
27
-
28
- if (definition.constant && !definition.null) {
29
- this._value = definition.value;
26
+ throw new FtAssertError('FGC60112', `${definition.metaName}, ${sequenceItem.fieldDefinition?.metaName}`);
27
+ } else {
28
+ if (definition.constant && !definition.null) {
29
+ this._value = definition.value;
30
+ }
30
31
  }
31
32
  }
32
33
 
@@ -34,104 +35,54 @@ export abstract class FtGenericField<T> extends FtField {
34
35
  return super.definition_ as FtGenericFieldDefinition<T>;
35
36
  }
36
37
 
37
- get value(): T {
38
- return this.getValueOrThrowNull();
38
+ override get value(): T {
39
+ if (this.isNull()) {
40
+ throw new Error(`Attempt to get value from null field "${this.name}"`);
41
+ } else {
42
+ return this._value;
43
+ }
39
44
  }
40
45
 
41
- set value(val: T) {
46
+ override set value(val: T) {
42
47
  this.setValue(val); // ignore fieldsAffectedFromIndex for direct value sets, as sequence redirects are not expected in this case
43
48
  }
44
49
 
50
+ override get nullableValue(): T | null {
51
+ return this.isNull() ? null : this._value;
52
+ }
53
+
54
+ override set nullableValue(value: T | null) {
55
+ if (value === null) {
56
+ this.setNull();
57
+ } else {
58
+ this.setValue(value);
59
+ }
60
+ }
61
+
45
62
  setValue(val: T): number {
46
63
  if (this.constant) {
47
64
  throw new Error(`Cannot set constant field "${this.name}"`);
48
65
  } else {
49
66
  this.clearNonConstantNull();
50
67
  this._value = val;
51
- this.valueAssigned = true;
68
+ this._valueAssigned = true;
52
69
  return this.checkValueSequenceRedirect(); // returns fieldsAffectedFromIndex
53
70
  }
54
71
  }
55
72
 
56
- protected getAsNonNullValueText(): string {
73
+ formatValue(): string {
57
74
  try {
58
- return this.definition_.getValueText(this._value);
75
+ return this.definition_.formatValue(this._value);
59
76
  } catch (error) {
60
77
  const message = error instanceof Error ? error.message : String(error);
61
78
  throw new Error(`Failed to convert field "${this.name}" to text: ${message}`, { cause: error });
62
79
  }
63
80
  }
64
81
 
65
- protected getAsNonNullObject(): unknown {
82
+ protected getValue(): T {
66
83
  return this._value;
67
84
  }
68
85
 
69
- protected getAsNonNullString(): string {
70
- return String(this._value);
71
- }
72
-
73
- protected getAsBoolean(): boolean {
74
- return Boolean(this._value);
75
- }
76
-
77
- protected getAsInteger(): number {
78
- return Number(this._value);
79
- }
80
-
81
- protected getAsBigInt(): bigint {
82
- if (typeof this._value === 'bigint') {
83
- return this._value;
84
- }
85
- return BigInt(Number(this._value));
86
- }
87
-
88
- protected getAsFloat(): number {
89
- return Number(this._value);
90
- }
91
-
92
- protected getAsDateTime(): Date {
93
- if (this._value instanceof Date) {
94
- return this._value;
95
- }
96
- return new Date(Number(this._value));
97
- }
98
-
99
- protected getAsDecimal(): number {
100
- return Number(this._value);
101
- }
102
-
103
- protected setAsNonNullObject(newValue: unknown): void {
104
- this.value = newValue as T;
105
- }
106
-
107
- protected setAsNonNullString(newValue: string): void {
108
- this.value = newValue as unknown as T;
109
- }
110
-
111
- protected setAsBoolean(newValue: boolean): void {
112
- this.value = newValue as unknown as T;
113
- }
114
-
115
- protected setAsInteger(newValue: number): void {
116
- this.value = newValue as unknown as T;
117
- }
118
-
119
- protected setAsBigInt(newValue: bigint): void {
120
- this.value = newValue as unknown as T;
121
- }
122
-
123
- protected setAsFloat(newValue: number): void {
124
- this.value = newValue as unknown as T;
125
- }
126
-
127
- protected setAsDateTime(newValue: Date): void {
128
- this.value = newValue as unknown as T;
129
- }
130
-
131
- protected setAsDecimal(newValue: number): void {
132
- this.value = newValue as unknown as T;
133
- }
134
-
135
86
  protected getAsRedirectBoolean(): boolean {
136
87
  return Boolean(this._value);
137
88
  }
@@ -158,11 +109,11 @@ export abstract class FtGenericField<T> extends FtField {
158
109
  return Number(this._value);
159
110
  }
160
111
 
161
- protected loadNonNullValue(valueText: string): void {
112
+ protected override loadValueFromText(valueText: string): void {
162
113
  if (!this.constant) {
163
114
  this.clearNonConstantNull();
164
115
  this._value = this.definition_.parseValueText(valueText);
165
- this.valueAssigned = true;
116
+ this._valueAssigned = true;
166
117
  this.checkValueSequenceRedirect(); // ignore fieldsAffectedFromIndex for value loads, as sequence redirects are not expected in this case
167
118
  } else {
168
119
  if (this.isNull()) {
@@ -177,13 +128,6 @@ export abstract class FtGenericField<T> extends FtField {
177
128
  }
178
129
  }
179
130
 
180
- private getValueOrThrowNull(): T {
181
- if (this.isNull()) {
182
- throw new Error(`Attempt to get value from null field "${this.name}"`);
183
- }
184
- return this._value;
185
- }
186
-
187
131
  private checkValueSequenceRedirect(): number {
188
132
  if (this.sequenceRedirectList.count > 0 && !this.sidelined) {
189
133
  let redirected = false;
@@ -1,6 +1,9 @@
1
+ import { FtDataType } from '../../index.js';
1
2
  import { FtSequenceInvokation } from '../../sequences/core/ft-sequence-invokation.js';
2
3
  import { FtSequenceItem } from '../../sequences/core/ft-sequence-item.js';
3
4
  import { FtIntegerFieldDefinition } from '../definitions/ft-integer-field-definition.js';
5
+ import { FtFieldTypeError } from './errors/ft-field-type-error.js';
6
+ import { FtField } from './ft-field.js';
4
7
  import { FtGenericField } from './ft-generic-field.js';
5
8
 
6
9
  /**
@@ -26,18 +29,37 @@ export class FtIntegerField extends FtGenericField<bigint> {
26
29
  return this.definition.styles;
27
30
  }
28
31
 
29
- get nullableValue(): bigint | null {
30
- return this.isNull() ? null : this.value;
32
+ static cast(field: FtField): field is FtIntegerField {
33
+ return field.dataType === FtDataType.Integer;
31
34
  }
32
35
 
33
- set nullableValue(value: bigint | null) {
34
- if (value === null) {
35
- this.setNull();
36
- } else {
37
- this.value = value;
36
+ override setValue(newValue: FtField.Value): number {
37
+ switch (typeof newValue) {
38
+ case 'bigint':
39
+ return super.setValue(newValue);
40
+ case 'number':
41
+ return super.setValue(BigInt(newValue));
42
+ default:
43
+ throw new FtFieldTypeError(`Invalid type (${typeof newValue}) for integer field: ${this.name}`);
38
44
  }
39
45
  }
40
46
 
47
+ protected override getAsBigInt(): bigint {
48
+ return this.getValue();
49
+ }
50
+
51
+ protected override setAsBigInt(newValue: bigint): void {
52
+ super.setValue(newValue);
53
+ }
54
+
55
+ protected override getAsInteger(): number {
56
+ return Number(this.getValue());
57
+ }
58
+
59
+ protected override setAsInteger(newValue: number): void {
60
+ super.setValue(BigInt(newValue));
61
+ }
62
+
41
63
  protected isValueEqual(left: bigint, right: bigint): boolean {
42
64
  return left === right;
43
65
  }
@@ -1,6 +1,9 @@
1
1
  import { FtSequenceInvokation } from '../../sequences/core/ft-sequence-invokation.js';
2
2
  import { FtSequenceItem } from '../../sequences/core/ft-sequence-item.js';
3
+ import { FtDataType } from '../../types/enums/ft-data-type.js';
3
4
  import { FtStringFieldDefinition } from '../definitions/ft-string-field-definition.js';
5
+ import { FtFieldTypeError } from './errors/ft-field-type-error.js';
6
+ import { FtField } from './ft-field.js';
4
7
  import { FtGenericField } from './ft-generic-field.js';
5
8
 
6
9
  /**
@@ -14,24 +17,24 @@ export class FtStringField extends FtGenericField<string> {
14
17
  super(sequenceInvokation, sequenceItem, FtStringField.VALUE_TEXT_NULL_TRIMMABLE, definition);
15
18
  }
16
19
 
17
- get nullableValue(): string | null {
18
- return this.isNull() ? null : this.value;
20
+ static cast(field: FtField): field is FtStringField {
21
+ return field.dataType === FtDataType.String;
19
22
  }
20
23
 
21
- set nullableValue(value: string | null) {
22
- if (value === null) {
23
- this.setNull();
24
+ override setValue(newValue: FtField.Value): number {
25
+ if (typeof newValue === 'string') {
26
+ return super.setValue(newValue);
24
27
  } else {
25
- this.value = value;
28
+ throw new FtFieldTypeError(`Invalid type (${typeof newValue}) for string field: ${this.name}`);
26
29
  }
27
30
  }
28
31
 
29
- override setValue(value: string | null): number {
30
- if (value === null) {
31
- return this.setNull(); // returns fieldsAffectedFromIndex
32
- } else {
33
- return super.setValue(value); // returns fieldsAffectedFromIndex
34
- }
32
+ protected override getAsString(): string {
33
+ return this.getValue();
34
+ }
35
+
36
+ protected override setAsString(newValue: string): void {
37
+ super.setValue(newValue);
35
38
  }
36
39
 
37
40
  protected isValueEqual(left: string, right: string): boolean {
package/src/index.ts CHANGED
@@ -7,8 +7,6 @@ export {
7
7
  DotNetNumberStyles,
8
8
  } from '@pbkware/dot-net-date-number-formatting';
9
9
 
10
- export { Result } from '@pbkware/js-utils';
11
-
12
10
  // Enums
13
11
  export { FtBooleanStyles } from './types/enums/ft-boolean-styles.js';
14
12
  export { FtEndOfLineAutoWriteType } from './types/enums/ft-end-of-line-auto-write-type.js';
@@ -31,6 +29,11 @@ export { FtTruncateType } from './types/enums/ft-truncate-type.js';
31
29
  export { FtDataType } from './types/enums/ft-data-type.js';
32
30
  export { FtSequenceRedirectType } from './types/enums/ft-sequence-redirect-type.js';
33
31
 
32
+ // Utils
33
+ export { FtCommaText } from './utils/ft-comma-text.js';
34
+ export { FtInternalError } from './utils/ft-internal-error.js';
35
+ export { FtErr, FtOk, FtResult } from './utils/ft-result.js';
36
+
34
37
  // Core meta classes
35
38
  export { FtBooleanMetaField } from './meta/fields/ft-boolean-meta-field.js';
36
39
  export { FtDateTimeMetaField } from './meta/fields/ft-date-time-meta-field.js';
@@ -135,13 +138,19 @@ export { FtDateTimeStylesMetaSerialization } from './meta-serialization/styles/f
135
138
  export { FtNumberStylesMetaSerialization } from './meta-serialization/styles/ft-number-styles-meta-serialization.js';
136
139
 
137
140
  // Serialization errors and exceptions
138
- export { FtSerializationError } from './types/errors/ft-serialization-error.js';
139
- export { FtSerializationException } from './types/errors/ft-serialization-exception.js';
141
+ export { FtFieldNullError as FtNullError } from './fields/instances/errors/ft-field-null-error.js';
142
+ export { FtFieldTypeError as FtTypeError } from './fields/instances/errors/ft-field-type-error.js';
143
+ export { FtSerializationErrorCode } from './serialization/ft-serialization-error-code.js';
144
+ export { FtSerializationError } from './serialization/ft-serialization-error.js';
145
+
146
+ // Serialization core
147
+ export { FtSerializationCore } from './serialization/ft-serialization-core.js';
140
148
 
141
149
  // Serialization reader
142
150
  export { FtDeclaredParameterRec, FtDeclaredParameters } from './serialization/ft-declared-parameters.js';
143
151
  export { FtSerializationReader } from './serialization/ft-serialization-reader.js';
144
- export { FtStringReader, FtTextReader } from './serialization/ft-text-reader.js';
152
+ export { FtStringReader } from './serialization/text-reader/ft-string-reader.js';
153
+ export { FtTextReader } from './serialization/text-reader/ft-text-reader.js';
145
154
 
146
155
  // Serialization writer
147
156
  export { FtWriterSettings } from './api/ft-writer-settings.js';
@@ -158,28 +167,28 @@ export { FtWriter } from './api/ft-writer.js';
158
167
  /**
159
168
  * @public
160
169
  */
161
- export type { FtFieldHeadingReadyEventArgs } from './types/events/ft-field-heading-ready-event-args.js';
170
+ export type { FtFieldHeadingReadyEventArgs } from './serialization/events/ft-field-heading-ready-event-args.js';
162
171
  /**
163
172
  * @public
164
173
  */
165
- export type { FtFieldValueReadyEventArgs } from './types/events/ft-field-value-ready-event-args.js';
174
+ export type { FtFieldValueReadyEventArgs } from './serialization/events/ft-field-value-ready-event-args.js';
166
175
  /**
167
176
  * @public
168
177
  */
169
- export type { FtHeadingLineFinishedEventArgs } from './types/events/ft-heading-line-finished-event-args.js';
178
+ export type { FtHeadingLineFinishedEventArgs } from './serialization/events/ft-heading-line-finished-event-args.js';
170
179
  /**
171
180
  * @public
172
181
  */
173
- export type { FtHeadingLineStartedEventArgs } from './types/events/ft-heading-line-started-event-args.js';
182
+ export type { FtHeadingLineStartedEventArgs } from './serialization/events/ft-heading-line-started-event-args.js';
174
183
  /**
175
184
  * @public
176
185
  */
177
- export type { FtRecordFinishedEventArgs } from './types/events/ft-record-finished-event-args.js';
186
+ export type { FtRecordFinishedEventArgs } from './serialization/events/ft-record-finished-event-args.js';
178
187
  /**
179
188
  * @public
180
189
  */
181
- export type { FtRecordStartedEventArgs } from './types/events/ft-record-started-event-args.js';
190
+ export type { FtRecordStartedEventArgs } from './serialization/events/ft-record-started-event-args.js';
182
191
  /**
183
192
  * @public
184
193
  */
185
- export type { FtSequenceRedirectedEventArgs } from './types/events/ft-sequence-redirected-event-args.js';
194
+ export type { FtSequenceRedirectedEventArgs } from './serialization/events/ft-sequence-redirected-event-args.js';
@@ -18,12 +18,13 @@ export class FtMetaSequenceList {
18
18
  return this._list[index];
19
19
  }
20
20
 
21
- getByName(name: string): FtMetaSequence {
21
+ getByName(name: string): FtMetaSequence | undefined {
22
22
  const index = this.indexOfName(name);
23
23
  if (index < 0) {
24
- throw new Error(`Meta sequence not found: ${name}`);
24
+ return undefined;
25
+ } else {
26
+ return this._list[index];
25
27
  }
26
- return this._list[index];
27
28
  }
28
29
 
29
30
  set(value: readonly FtMetaSequence[]): void {
@@ -1,7 +1,7 @@
1
1
  // Meta sequence redirect list - manages redirects for a sequence item
2
2
 
3
3
  import { FtSequenceRedirectType } from '../../../types/enums/ft-sequence-redirect-type.js';
4
- import { FtUnreachableCaseError } from '../../../types/errors/ft-internal-error.js';
4
+ import { FtUnreachableCaseError } from '../../../utils/ft-internal-error.js';
5
5
  import type { FtMetaSequenceList } from '../core/ft-meta-sequence-list.js';
6
6
  import { FtBooleanMetaSequenceRedirect } from './ft-boolean-meta-sequence-redirect.js';
7
7
  import { FtCaseInsensitiveStringMetaSequenceRedirect } from './ft-case-insensitive-string-meta-sequence-redirect.js';
@@ -1,4 +1,3 @@
1
- import { CommaText } from '@pbkware/js-utils';
2
1
  import XMLBuilder from 'fast-xml-builder';
3
2
  import { XMLParser } from 'fast-xml-parser';
4
3
  import { FtFieldFactory } from '../../factory/ft-field-factory.js';
@@ -27,7 +26,8 @@ import { FtNullMetaSequenceRedirect } from '../../meta/sequences/redirects/ft-nu
27
26
  import { FtMetaSubstitution } from '../../meta/substitutions/ft-meta-substitution-list.js';
28
27
  import { FtDataType } from '../../types/enums/ft-data-type.js';
29
28
  import { FtSequenceRedirectType } from '../../types/enums/ft-sequence-redirect-type.js';
30
- import { FtAssertError, FtUnreachableCaseError } from '../../types/errors/ft-internal-error.js';
29
+ import { FtCommaText } from '../../utils/ft-comma-text.js';
30
+ import { FtAssertError, FtUnreachableCaseError } from '../../utils/ft-internal-error.js';
31
31
  import { FtBooleanStylesMetaSerialization } from '../styles/ft-boolean-styles-meta-serialization.js';
32
32
  import { FtDateTimeStylesMetaSerialization } from '../styles/ft-date-time-styles-meta-serialization.js';
33
33
  import { FtNumberStylesMetaSerialization } from '../styles/ft-number-styles-meta-serialization.js';
@@ -236,9 +236,6 @@ export class FtXmlMetaSerialization {
236
236
  const sequenceNameResolver = new MetaSerializationSequenceNameResolver();
237
237
  const redirectSequenceResolver = new MetaSerializationRedirectSequenceResolver(sequenceNameResolver);
238
238
 
239
- const redirectNames = new Array<MetaSerializationRedirectSequenceResolver.Rec>(sequenceCount); // We need to collect redirect names first before we can resolve them, so we create records with redirect names and resolve after deserializing all sequences
240
- const sequenceNameRecs = new Array<MetaSerializationSequenceNameResolver.Rec>(sequenceCount);
241
-
242
239
  for (let i = 0; i < sequenceCount; i++) {
243
240
  const seqObj = objSequences[i];
244
241
  const sequenceNameRec = this.deserializeSequence(seqObj, resolvedOrderedFieldList, redirectSequenceResolver, warnings);
@@ -296,7 +293,7 @@ export class FtXmlMetaSerialization {
296
293
  '@_HeadingTruncateType': TruncateTypeMetaSerialization.serialize(field.headingTruncateType, true, meta.headingTruncateType),
297
294
  '@_HeadingTruncateChar': CharMetaSerialization.serialize(field.headingTruncateChar, meta.headingTruncateChar),
298
295
  '@_HeadingEndOfValueChar': CharMetaSerialization.serialize(field.headingEndOfValueChar, meta.headingEndOfValueChar),
299
- '@_Headings': fieldHeadings.length === 0 ? undefined : StringMetaSerialization.serialize(CommaText.fromStringArray(fieldHeadings)),
296
+ '@_Headings': fieldHeadings.length === 0 ? undefined : StringMetaSerialization.serialize(FtCommaText.fromStringArray(fieldHeadings)),
300
297
  };
301
298
 
302
299
  // Type-specific properties
@@ -598,7 +595,7 @@ export class FtXmlMetaSerialization {
598
595
  // Headings
599
596
  if (headingLineCount > 0) {
600
597
  const headingsCommaText = StringMetaSerialization.deserialize(obj['@_Headings'], '', warnings);
601
- const headingsResult = CommaText.tryToStringArray(headingsCommaText, true);
598
+ const headingsResult = FtCommaText.tryToStringArray(headingsCommaText, true);
602
599
  if (headingsResult.isErr()) {
603
600
  warnings.push(`Headings: Invalid: Field ${field.name}: Value: "${headingsCommaText}"`);
604
601
  } else {
@@ -1,7 +1,7 @@
1
1
  import { DotNetNumberStyles } from '@pbkware/dot-net-date-number-formatting';
2
2
  import { FtMetaDefaults } from '../../meta/ft-meta-defaults.js';
3
3
  import { FtDataType, FtNumberDataType } from '../../types/enums/ft-data-type.js';
4
- import { FtUnreachableCaseError } from '../../types/errors/ft-internal-error.js';
4
+ import { FtUnreachableCaseError } from '../../utils/ft-internal-error.js';
5
5
 
6
6
  /** @public */
7
7
  // eslint-disable-next-line @typescript-eslint/no-extraneous-class
@@ -1,5 +1,5 @@
1
- import { parseIntStrict } from '@pbkware/js-utils';
2
1
  import { FtMetaDefaults } from '../../meta/ft-meta-defaults.js';
2
+ import { parseIntStrict } from '../../utils/number-parse.js';
3
3
 
4
4
  // eslint-disable-next-line @typescript-eslint/no-extraneous-class
5
5
  export class DateTimeMetaSerialization {
@@ -1,18 +1,18 @@
1
- import { Err, Ok, Result } from '@pbkware/js-utils';
2
1
  import { FtMetaElementType } from '../../../types/enums/ft-meta-element-type.js';
2
+ import { FtErr, FtOk, FtResult } from '../../../utils/ft-result.js';
3
3
 
4
4
  export namespace MetaElementTypeMetaSerialization {
5
5
  export function serialize(value: FtMetaElementType): string {
6
6
  return serializeMap[value];
7
7
  }
8
8
 
9
- export function deserialize(value: string): Result<FtMetaElementType> {
9
+ export function deserialize(value: string): FtResult<FtMetaElementType> {
10
10
  const deserializedValue = deserializeMap[value.trim()];
11
11
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
12
12
  if (deserializedValue === undefined) {
13
- return new Err(`MetaElementType: Value: ${value}`);
13
+ return new FtErr(`MetaElementType: Value: ${value}`);
14
14
  } else {
15
- return new Ok(deserializedValue);
15
+ return new FtOk(deserializedValue);
16
16
  }
17
17
  }
18
18
  }
@@ -1,7 +1,7 @@
1
1
  import { FtMetaDefaults } from '../../../meta/ft-meta-defaults.js';
2
2
  import { FtDataType } from '../../../types/enums/ft-data-type.js';
3
3
  import { FtSequenceRedirectType } from '../../../types/enums/ft-sequence-redirect-type.js';
4
- import { FtUnreachableCaseError } from '../../../types/errors/ft-internal-error.js';
4
+ import { FtUnreachableCaseError } from '../../../utils/ft-internal-error.js';
5
5
 
6
6
  export namespace SequenceRedirectTypeMetaSerialization {
7
7
  export const stringDefaultValue = FtMetaDefaults.StringField.SequenceRedirectType;
@@ -1,5 +1,5 @@
1
- import { isDigitCharCode } from '@pbkware/js-utils';
2
- import { FtAssertError } from '../../types/errors/ft-internal-error.js';
1
+ import { FtAssertError } from '../../utils/ft-internal-error.js';
2
+ import { isDigitCharCode } from '../../utils/number-parse.js';
3
3
 
4
4
  // eslint-disable-next-line @typescript-eslint/no-extraneous-class
5
5
  export class FloatMetaSerialization {
@@ -1,5 +1,5 @@
1
- import { parseIntStrict } from '@pbkware/js-utils';
2
- import { FtAssertError } from '../../types/errors/ft-internal-error.js';
1
+ import { FtAssertError } from '../../utils/ft-internal-error.js';
2
+ import { parseIntStrict } from '../../utils/number-parse.js';
3
3
 
4
4
  // eslint-disable-next-line @typescript-eslint/no-extraneous-class
5
5
  export class IntegerFloatMetaSerialization {
@@ -1,4 +1,8 @@
1
- export interface ImplicitExplicitIndexSortRec<T> {
1
+ import { FtMetaField } from '../../meta/fields/ft-meta-field.js';
2
+ import { FtMetaSequenceItem } from '../../meta/sequences/core/ft-meta-sequence-item.js';
3
+ import { MetaSerializationRedirectSequenceResolver } from './meta-serialization-redirect-sequence-resolver.js';
4
+
5
+ export interface ImplicitExplicitIndexSortRec<T extends FtMetaField | FtMetaSequenceItem | MetaSerializationRedirectSequenceResolver.Rec> {
2
6
  target: T;
3
7
  implicitIndex: number;
4
8
  explicitIndex: number;
@@ -7,7 +11,10 @@ export interface ImplicitExplicitIndexSortRec<T> {
7
11
  export namespace ImplicitExplicitIndexSortRec {
8
12
  export const INDEX_NOT_SET = -1;
9
13
 
10
- export function compare(left: ImplicitExplicitIndexSortRec<unknown>, right: ImplicitExplicitIndexSortRec<unknown>): number {
14
+ export function compare<T extends FtMetaField | FtMetaSequenceItem | MetaSerializationRedirectSequenceResolver.Rec>(
15
+ left: ImplicitExplicitIndexSortRec<T>,
16
+ right: ImplicitExplicitIndexSortRec<T>,
17
+ ): number {
11
18
  const leftHasExplicit = left.explicitIndex !== INDEX_NOT_SET;
12
19
  const rightHasExplicit = right.explicitIndex !== INDEX_NOT_SET;
13
20
 
@@ -28,22 +35,21 @@ export namespace ImplicitExplicitIndexSortRec {
28
35
  return result;
29
36
  }
30
37
 
31
- export function checkSortedArray(arr: ImplicitExplicitIndexSortRec<unknown>[], targetType: string, warnings: string[]): void {
32
- let negativeWarned = false;
38
+ export function checkSortedArray<T extends FtMetaField | FtMetaSequenceItem | MetaSerializationRedirectSequenceResolver.Rec>(
39
+ arr: ImplicitExplicitIndexSortRec<T>[],
40
+ targetType: string,
41
+ warnings: string[],
42
+ ): void {
33
43
  let outOfBoundsWarned = false;
34
44
  let duplicateWarned = false;
35
45
 
36
46
  const count = arr.length;
37
47
  for (let i = 1; i < arr.length; i++) {
38
48
  const rec = arr[i];
39
- if (rec.explicitIndex !== i) {
40
- if (rec.explicitIndex < 0) {
41
- if (!negativeWarned) {
42
- warnings.push(`One or more negative explicit index: ${targetType}`);
43
- negativeWarned = true;
44
- }
45
- } else {
46
- if (rec.explicitIndex >= count) {
49
+ const explicitIndex = rec.explicitIndex;
50
+ if (explicitIndex >= 0) {
51
+ if (explicitIndex !== i) {
52
+ if (explicitIndex >= count) {
47
53
  if (!outOfBoundsWarned) {
48
54
  warnings.push(`One or more explicit index out of bounds: ${targetType}`);
49
55
  outOfBoundsWarned = true;
@@ -31,20 +31,43 @@ export class MetaSerializationSequenceNameResolver {
31
31
  const count = recs.length;
32
32
  const sequences = new Array<FtMetaSequence>(count);
33
33
 
34
+ let rootSequence: FtMetaSequence | undefined;
35
+
34
36
  for (let i = 0; i < count; i++) {
35
37
  const rec = recs[i];
36
- sequences[i] = rec.sequence;
38
+ const sequence = rec.sequence;
39
+ if (sequence.root) {
40
+ if (rootSequence === undefined) {
41
+ rootSequence = sequence;
42
+ } else {
43
+ warnings.push(`Multiple root sequences found: ${rootSequence.name} and ${sequence.name}`);
44
+ sequence.root = false;
45
+ }
46
+ }
47
+ sequences[i] = sequence;
37
48
  const sequenceName = rec.name;
38
49
  if (sequenceName === undefined) {
39
50
  warnings.push(`Sequence with undefined name: ${JSON.stringify(rec.sequence)}`);
40
51
  } else {
41
- const existingRec = this._recs.find((r) => r.name === sequenceName);
52
+ const existingRec = this._recs.find((r, findIndex) => findIndex !== i && r.name === sequenceName);
42
53
  if (existingRec !== undefined) {
43
54
  warnings.push(`Duplicate sequence name: ${sequenceName}`);
44
55
  }
45
56
  this._recs.push(rec);
46
57
  }
47
58
  }
59
+
60
+ if (rootSequence === undefined) {
61
+ warnings.push(`No root sequence found. Setting the first sequence as root: ${sequences[0].name}`);
62
+ sequences[0].root = true;
63
+ } else {
64
+ const rootIndex = sequences.indexOf(rootSequence);
65
+ if (rootIndex > 0) {
66
+ // Make sure the root sequence is first in the list
67
+ sequences.splice(rootIndex, 1);
68
+ sequences.unshift(rootSequence);
69
+ }
70
+ }
48
71
  return sequences;
49
72
  }
50
73