jspurefix 4.1.2 → 5.0.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 (156) hide show
  1. package/BACKPORT_PLAN.md +214 -0
  2. package/data/examples/FIX.4.4/fixsim/fix.txt +46 -0
  3. package/data/session/fixsim-qf44-initiator.json +21 -0
  4. package/dist/buffer/ascii/ascii-segment-parser.js +36 -0
  5. package/dist/buffer/ascii/ascii-segment-parser.js.map +1 -1
  6. package/dist/buffer/ascii/tag-index.d.ts +20 -0
  7. package/dist/buffer/ascii/tag-index.js +89 -0
  8. package/dist/buffer/ascii/tag-index.js.map +1 -0
  9. package/dist/buffer/msg-view.js +17 -4
  10. package/dist/buffer/msg-view.js.map +1 -1
  11. package/dist/buffer/segment/segment-description.d.ts +3 -0
  12. package/dist/buffer/segment/segment-description.js +8 -0
  13. package/dist/buffer/segment/segment-description.js.map +1 -1
  14. package/dist/buffer/segment/segment-view.d.ts +13 -0
  15. package/dist/buffer/segment/segment-view.js +27 -0
  16. package/dist/buffer/segment/segment-view.js.map +1 -0
  17. package/dist/collections/collection.js.map +1 -1
  18. package/dist/config/js-fix-logger.js.map +1 -1
  19. package/dist/store/fix-msg-ascii-store-resend.js.map +1 -1
  20. package/dist/transport/tcp/tcp-initiator-connector.js.map +1 -1
  21. package/dist/types/FIX.5.0SP2/quickfix/enum/all-enum.js.map +1 -1
  22. package/dist/types/FIX.5.0SP2/repo/enum/all-enum.js.map +1 -1
  23. package/dist/types/FIX.5.0SP2/repo/set/hop_grp.js.map +1 -1
  24. package/dist/types/FIX4.0/repo/enum/all-enum.js.map +1 -1
  25. package/dist/types/FIX4.1/repo/enum/all-enum.js.map +1 -1
  26. package/dist/types/FIX4.2/quickfix/enum/all-enum.js.map +1 -1
  27. package/dist/types/FIX4.2/repo/enum/all-enum.js.map +1 -1
  28. package/dist/types/FIX4.3/quickfix/enum/all-enum.js.map +1 -1
  29. package/dist/types/FIX4.3/repo/allocation.js.map +1 -1
  30. package/dist/types/FIX4.3/repo/allocation_ack.js.map +1 -1
  31. package/dist/types/FIX4.3/repo/cross_order_cancel_replace_request.js.map +1 -1
  32. package/dist/types/FIX4.3/repo/cross_order_cancel_request.js.map +1 -1
  33. package/dist/types/FIX4.3/repo/derivative_security_list.js.map +1 -1
  34. package/dist/types/FIX4.3/repo/enum/all-enum.js.map +1 -1
  35. package/dist/types/FIX4.3/repo/execution_report.js.map +1 -1
  36. package/dist/types/FIX4.3/repo/mass_quote.js.map +1 -1
  37. package/dist/types/FIX4.3/repo/mass_quote_acknowledgement.js.map +1 -1
  38. package/dist/types/FIX4.3/repo/multileg_order_cancel_replace_request.js.map +1 -1
  39. package/dist/types/FIX4.3/repo/new_order_cross.js.map +1 -1
  40. package/dist/types/FIX4.3/repo/new_order_list.js.map +1 -1
  41. package/dist/types/FIX4.3/repo/new_order_multileg.js.map +1 -1
  42. package/dist/types/FIX4.3/repo/new_order_single.js.map +1 -1
  43. package/dist/types/FIX4.3/repo/order_cancel_replace_request.js.map +1 -1
  44. package/dist/types/FIX4.3/repo/order_cancel_request.js.map +1 -1
  45. package/dist/types/FIX4.3/repo/order_mass_status_request.js.map +1 -1
  46. package/dist/types/FIX4.3/repo/order_status_request.js.map +1 -1
  47. package/dist/types/FIX4.3/repo/quote.js.map +1 -1
  48. package/dist/types/FIX4.3/repo/quote_cancel.js.map +1 -1
  49. package/dist/types/FIX4.3/repo/quote_request.js.map +1 -1
  50. package/dist/types/FIX4.3/repo/quote_request_reject.js.map +1 -1
  51. package/dist/types/FIX4.3/repo/quote_status_report.js.map +1 -1
  52. package/dist/types/FIX4.3/repo/quote_status_request.js.map +1 -1
  53. package/dist/types/FIX4.3/repo/registration_instructions.js.map +1 -1
  54. package/dist/types/FIX4.3/repo/registration_instructions_response.js.map +1 -1
  55. package/dist/types/FIX4.3/repo/security_definition.js.map +1 -1
  56. package/dist/types/FIX4.3/repo/security_definition_request.js.map +1 -1
  57. package/dist/types/FIX4.3/repo/security_list.js.map +1 -1
  58. package/dist/types/FIX4.3/repo/settlement_instructions.js.map +1 -1
  59. package/dist/types/FIX4.3/repo/trade_capture_report.js.map +1 -1
  60. package/dist/types/FIX4.3/repo/trade_capture_report_request.js.map +1 -1
  61. package/dist/types/FIX4.4/quickfix/enum/all-enum.js.map +1 -1
  62. package/dist/types/FIX4.4/repo/enum/all-enum.js.map +1 -1
  63. package/dist/types/FIX4.4/repo/set/hop.js.map +1 -1
  64. package/dist/types/FIXML50SP2/adjusted_position_report.js.map +1 -1
  65. package/dist/types/FIXML50SP2/derivative_security_list.js.map +1 -1
  66. package/dist/types/FIXML50SP2/derivative_security_list_update_report.js.map +1 -1
  67. package/dist/types/FIXML50SP2/email.js.map +1 -1
  68. package/dist/types/FIXML50SP2/enum/all-enum.js.map +1 -1
  69. package/dist/types/FIXML50SP2/news.js.map +1 -1
  70. package/dist/types/FIXML50SP2/quote_cancel.js.map +1 -1
  71. package/dist/types/FIXML50SP2/set/market_segment_grp.js.map +1 -1
  72. package/dist/types/FIXML50SP2/set/party_risk_limits_ack_grp.js.map +1 -1
  73. package/dist/types/FIXML50SP2/set/party_risk_limits_grp.js.map +1 -1
  74. package/dist/types/FIXML50SP2/set/party_risk_limits_update_grp.js.map +1 -1
  75. package/dist/types/FIXML50SP2/set/sec_list_grp.js.map +1 -1
  76. package/dist/types/FIXML50SP2/set/sec_lst_upd_rel_sym_grp.js.map +1 -1
  77. package/dist/types/FIXML50SP2/set/trading_session_rules_grp.js.map +1 -1
  78. package/dist/types/FIXML50SP2/set/trd_instrmt_leg_grp.js.map +1 -1
  79. package/dist/types/FIXML50SP2/set/trd_sess_lst_grp.js.map +1 -1
  80. package/dist/types/FIXML50SP2/stream_assignment_report.js.map +1 -1
  81. package/dist/types/FIXML50SP2/stream_assignment_request.js.map +1 -1
  82. package/eslint.config.mjs +119 -0
  83. package/jsfix.test_client.txt +66 -66
  84. package/jsfix.test_server.txt +63 -63
  85. package/package.json +4 -5
  86. package/src/buffer/ascii/ascii-segment-parser.ts +37 -0
  87. package/src/buffer/ascii/tag-index.ts +101 -0
  88. package/src/buffer/msg-view.ts +18 -6
  89. package/src/buffer/segment/segment-description.ts +10 -0
  90. package/src/buffer/segment/segment-view.ts +28 -0
  91. package/src/collections/collection.ts +0 -1
  92. package/src/config/js-fix-logger.ts +0 -1
  93. package/src/store/fix-msg-ascii-store-resend.ts +1 -1
  94. package/src/transport/tcp/tcp-initiator-connector.ts +1 -1
  95. package/src/types/FIX.5.0SP2/quickfix/enum/all-enum.ts +0 -1
  96. package/src/types/FIX.5.0SP2/repo/enum/all-enum.ts +0 -1
  97. package/src/types/FIX.5.0SP2/repo/set/hop_grp.ts +1 -1
  98. package/src/types/FIX4.0/repo/enum/all-enum.ts +0 -1
  99. package/src/types/FIX4.1/repo/enum/all-enum.ts +0 -1
  100. package/src/types/FIX4.2/quickfix/enum/all-enum.ts +0 -1
  101. package/src/types/FIX4.2/repo/enum/all-enum.ts +0 -1
  102. package/src/types/FIX4.3/quickfix/enum/all-enum.ts +0 -1
  103. package/src/types/FIX4.3/repo/allocation.ts +2 -2
  104. package/src/types/FIX4.3/repo/allocation_ack.ts +1 -1
  105. package/src/types/FIX4.3/repo/cross_order_cancel_replace_request.ts +4 -4
  106. package/src/types/FIX4.3/repo/cross_order_cancel_request.ts +1 -1
  107. package/src/types/FIX4.3/repo/derivative_security_list.ts +1 -1
  108. package/src/types/FIX4.3/repo/enum/all-enum.ts +0 -1
  109. package/src/types/FIX4.3/repo/execution_report.ts +5 -5
  110. package/src/types/FIX4.3/repo/mass_quote.ts +1 -1
  111. package/src/types/FIX4.3/repo/mass_quote_acknowledgement.ts +1 -1
  112. package/src/types/FIX4.3/repo/multileg_order_cancel_replace_request.ts +3 -3
  113. package/src/types/FIX4.3/repo/new_order_cross.ts +4 -4
  114. package/src/types/FIX4.3/repo/new_order_list.ts +4 -4
  115. package/src/types/FIX4.3/repo/new_order_multileg.ts +3 -3
  116. package/src/types/FIX4.3/repo/new_order_single.ts +4 -4
  117. package/src/types/FIX4.3/repo/order_cancel_replace_request.ts +3 -3
  118. package/src/types/FIX4.3/repo/order_cancel_request.ts +1 -1
  119. package/src/types/FIX4.3/repo/order_mass_status_request.ts +1 -1
  120. package/src/types/FIX4.3/repo/order_status_request.ts +1 -1
  121. package/src/types/FIX4.3/repo/quote.ts +1 -1
  122. package/src/types/FIX4.3/repo/quote_cancel.ts +1 -1
  123. package/src/types/FIX4.3/repo/quote_request.ts +2 -2
  124. package/src/types/FIX4.3/repo/quote_request_reject.ts +2 -2
  125. package/src/types/FIX4.3/repo/quote_status_report.ts +1 -1
  126. package/src/types/FIX4.3/repo/quote_status_request.ts +1 -1
  127. package/src/types/FIX4.3/repo/registration_instructions.ts +2 -2
  128. package/src/types/FIX4.3/repo/registration_instructions_response.ts +1 -1
  129. package/src/types/FIX4.3/repo/security_definition.ts +1 -1
  130. package/src/types/FIX4.3/repo/security_definition_request.ts +1 -1
  131. package/src/types/FIX4.3/repo/security_list.ts +1 -1
  132. package/src/types/FIX4.3/repo/settlement_instructions.ts +1 -1
  133. package/src/types/FIX4.3/repo/trade_capture_report.ts +1 -1
  134. package/src/types/FIX4.3/repo/trade_capture_report_request.ts +1 -1
  135. package/src/types/FIX4.4/quickfix/enum/all-enum.ts +0 -1
  136. package/src/types/FIX4.4/repo/enum/all-enum.ts +0 -1
  137. package/src/types/FIX4.4/repo/set/hop.ts +1 -1
  138. package/src/types/FIXML50SP2/adjusted_position_report.ts +1 -1
  139. package/src/types/FIXML50SP2/derivative_security_list.ts +1 -1
  140. package/src/types/FIXML50SP2/derivative_security_list_update_report.ts +1 -1
  141. package/src/types/FIXML50SP2/email.ts +1 -1
  142. package/src/types/FIXML50SP2/enum/all-enum.ts +0 -1
  143. package/src/types/FIXML50SP2/news.ts +1 -1
  144. package/src/types/FIXML50SP2/quote_cancel.ts +1 -1
  145. package/src/types/FIXML50SP2/set/market_segment_grp.ts +1 -1
  146. package/src/types/FIXML50SP2/set/party_risk_limits_ack_grp.ts +1 -1
  147. package/src/types/FIXML50SP2/set/party_risk_limits_grp.ts +1 -1
  148. package/src/types/FIXML50SP2/set/party_risk_limits_update_grp.ts +1 -1
  149. package/src/types/FIXML50SP2/set/sec_list_grp.ts +2 -2
  150. package/src/types/FIXML50SP2/set/sec_lst_upd_rel_sym_grp.ts +1 -1
  151. package/src/types/FIXML50SP2/set/trading_session_rules_grp.ts +1 -1
  152. package/src/types/FIXML50SP2/set/trd_instrmt_leg_grp.ts +1 -1
  153. package/src/types/FIXML50SP2/set/trd_sess_lst_grp.ts +1 -1
  154. package/src/types/FIXML50SP2/stream_assignment_report.ts +1 -1
  155. package/src/types/FIXML50SP2/stream_assignment_request.ts +1 -1
  156. package/src/util/unzip.js +0 -1
@@ -0,0 +1,214 @@
1
+ # Backport Plan: C# cspurefix → TypeScript jspurefix
2
+
3
+ ## Background
4
+
5
+ The C# dotnet core port (`~/dev/cs/cspurefix`) has accumulated significant improvements over the TypeScript version which has had no real improvements for some time. The two codebases are structurally very similar, making incremental backporting feasible. The goal is to bring the TS version up to the same quality level through careful, non-disruptive changes.
6
+
7
+ A standalone demo at `~/dev/cs/purefix-standalone-demo` demonstrates the C# store/recovery working end-to-end including restart scenarios and extended soak testing.
8
+
9
+ ---
10
+
11
+ ## Phase 1: Non-Contiguous Tag Parsing (Correctness Fix)
12
+
13
+ **Priority: Highest | Risk: Medium | Scope: Contained to `src/buffer/`**
14
+
15
+ ### Problem
16
+
17
+ The TS segment parser assumes component tags appear in a contiguous block within the message body. Some brokers (discovered when using the C# engine) send messages where root-level component tags are scattered. For example, an Instrument component's tags (Symbol=55, SecurityIDSource=22, SecurityID=48) can be interleaved with non-Instrument tags (HandlInst=21, OrderQty=38, OrdType=40, Price=44, Side=54).
18
+
19
+ This is valid FIX — the spec does not require component tags to be contiguous at the root level. The TS parser fails to correctly resolve these messages.
20
+
21
+ ### Example (from fixsim-examples.txt NewOrderSingle)
22
+
23
+ ```
24
+ 8=FIX.4.4|9=193|35=D|34=5|49=FIXSIMDEMO|52=20241013-14:09:45.126|56=sjames8888@gmail_com|
25
+ 11=567638644253361428000|15=GBP|21=2|22=5|38=100|40=2|44=100|48=VOD.L|54=1|55=VOD.L|
26
+ 59=0|60=20241013-14:09:45.126|388=1|10=091|
27
+ ```
28
+
29
+ Instrument tags (15, 22, 48, 55) are scattered among order tags (21, 38, 40, 44, 54, 59, 60).
30
+
31
+ ### C# Solution
32
+
33
+ | File | Purpose |
34
+ |------|---------|
35
+ | `PureFix.Buffer/Ascii/AsciiSegmentParser.cs` | Stack-based parser with fragment detection |
36
+ | `PureFix.Buffer/Ascii/AsciiSegmentParser.Context.cs` | Parse state with `ExitedDepth1Components` and `FragmentedComponents` tracking |
37
+ | `PureFix.Buffer/Ascii/TagIndex.cs` | Indexes tags for non-contiguous access via `_tagSpans` dictionary |
38
+ | `PureFix.Buffer/Segment/SegmentView.cs` | Transparent access to scattered tags as if contiguous |
39
+ | `PureFix.Buffer/Segment/SegmentDescription.cs` | Segment metadata with position tracking |
40
+
41
+ **Algorithm:**
42
+
43
+ 1. **Discovery**: Stack-based recursive descent through tags. When a depth-1 component is popped from the stack, it's added to `ExitedDepth1Components`.
44
+ 2. **Fragment Detection**: If a tag belonging to an already-exited depth-1 component is encountered, that component is added to `FragmentedComponents`.
45
+ 3. **Optimised Access**: Only fragmented components get expensive `SegmentView` construction via `TagIndex`. Non-fragmented components use simple position ranges (no overhead).
46
+
47
+ ### TS Files to Modify
48
+
49
+ | File | Change |
50
+ |------|--------|
51
+ | `src/buffer/ascii/ascii-segment-parser.ts` | Add fragment detection (ExitedDepth1Components, FragmentedComponents tracking) |
52
+ | `src/buffer/segment/segment-description.ts` | May need SegmentView reference for fragmented components |
53
+ | New: `src/buffer/segment/segment-view.ts` | Port SegmentView for non-contiguous tag access |
54
+ | New: `src/buffer/ascii/tag-index.ts` | Port TagIndex for tag span indexing |
55
+
56
+ ### Test Data
57
+
58
+ Port from `~/dev/cs/cspurefix/PureFix.Test.ModularTypes/Data/examples/FIX.4.4/fixsim-examples.txt` — 46 real FIX messages including fragmented Instrument components. Write a failing test first to prove the problem, then fix.
59
+
60
+ ### C# Test Reference
61
+
62
+ `~/dev/cs/cspurefix/PureFix.Test.ModularTypes/FixSimTest.cs` — parses all 46 messages, verifies type counts, deserialises ExecutionReport to strongly-typed object.
63
+
64
+ ---
65
+
66
+ ## Phase 2: Parser Reset on Disconnect (Quick Win)
67
+
68
+ **Priority: High | Risk: Low | Scope: Small**
69
+
70
+ ### Problem
71
+
72
+ When a TCP connection drops mid-message, the ASCII parser retains partial buffer state. On reconnect, the stale buffer can corrupt the next message parse. The C# version explicitly resets the parser during reconnection preparation.
73
+
74
+ ### C# Solution
75
+
76
+ In `FixSession.cs` → `PrepareForReconnect()`:
77
+ ```csharp
78
+ m_parser.Reset();
79
+ ```
80
+
81
+ Also resets transient coordinator state (logon retry count, timeout recovery attempts) while preserving sequence numbers.
82
+
83
+ ### TS Files to Modify
84
+
85
+ | File | Change |
86
+ |------|--------|
87
+ | `src/transport/session/fix-session.ts` | Add parser reset in reconnection path |
88
+ | `src/buffer/ascii/ascii-parser.ts` | Ensure `reset()` method clears all partial state |
89
+
90
+ ---
91
+
92
+ ## Phase 3: SessionSequenceCoordinator (Foundation)
93
+
94
+ **Priority: High | Risk: Medium | Scope: Medium**
95
+
96
+ ### Problem
97
+
98
+ The TS version has sequence state scattered across `fix-session-state.ts` and `ascii-session.ts` with no single source of truth. This makes it hard to reason about recovery, reset, and reconnect behaviour. The C# version centralises all of this.
99
+
100
+ ### C# Solution
101
+
102
+ | File | Purpose |
103
+ |------|---------|
104
+ | `PureFix.Transport/Session/SessionSequenceCoordinator.cs` | Single source of truth for sender/target sequences |
105
+
106
+ **Key capabilities missing from TS:**
107
+
108
+ - `PrepareForReconnect()` — resets transient state, preserves sequences
109
+ - `HandlePeerReset()` — coordinates ResetSeqNumFlag=Y from peer
110
+ - `ResetAsAcceptor()` — acceptor-initiated reset
111
+ - `PossDupFlag` handling — messages with PossDupFlag=Y bypass normal sequence checks
112
+ - Logon retry with `MaxLogonRetries=100`
113
+ - Timeout recovery with `MaxTimeoutRecoveryAttempts=3` (handles sleep/wake scenarios)
114
+ - `ResendRequestManager` integration — storm protection, pending request tracking
115
+ - Delayed message acceptance — out-of-order messages that fill pending gap ranges
116
+
117
+ ### TS Files to Modify
118
+
119
+ | File | Change |
120
+ |------|--------|
121
+ | New: `src/transport/session/session-sequence-coordinator.ts` | Port coordinator |
122
+ | `src/transport/session/fix-session.ts` | Integrate coordinator as sequence authority |
123
+ | `src/transport/ascii/ascii-session.ts` | Replace inline sequence logic with coordinator calls |
124
+ | `src/transport/session/fix-session-state.ts` | May reduce scope — coordinator takes over sequence tracking |
125
+
126
+ ---
127
+
128
+ ## Phase 4: Persistent Message Store
129
+
130
+ **Priority: Medium-High | Risk: Medium | Scope: Medium**
131
+
132
+ ### Problem
133
+
134
+ The TS version only has `FixMsgMemoryStore` — all message history and sequence state is lost on process restart. The C# version has a QuickFix-compatible file store that persists across restarts.
135
+
136
+ ### C# Solution
137
+
138
+ | File | Purpose |
139
+ |------|---------|
140
+ | `PureFix.Transport/Store/IFixSessionStore.cs` | Unified persistence interface |
141
+ | `PureFix.Transport/Store/FileSessionStore.cs` | QuickFix-compatible file storage |
142
+ | `PureFix.Transport/Store/MemorySessionStore.cs` | In-memory implementation |
143
+ | `PureFix.Transport/Store/FileSessionStoreFactory.cs` | Factory pattern for store creation |
144
+ | `PureFix.Transport/Store/FixMsgStoreRecord.cs` | Persisted message record |
145
+
146
+ **QuickFix file format:**
147
+ - `.seqnums` — 20-char padded sender:target sequence numbers
148
+ - `.session` — creation timestamp
149
+ - `.header` — seqnum,offset,length index
150
+ - `.body` — raw FIX message bytes
151
+
152
+ ### Key Integration Points
153
+
154
+ - `StoreEncodedMessage()` — persist every sent message
155
+ - `InitializeSessionStore()` — load state on startup
156
+ - Store factory in config — deferred creation
157
+ - Store reset on `ResetSeqNumFlag=Y`
158
+ - Resender recreation after reset
159
+
160
+ ### TS Files to Modify
161
+
162
+ | File | Change |
163
+ |------|--------|
164
+ | New: `src/store/fix-session-store.ts` | Port IFixSessionStore interface |
165
+ | New: `src/store/file-session-store.ts` | Port FileSessionStore |
166
+ | New: `src/store/file-session-store-factory.ts` | Port factory |
167
+ | `src/store/fix-msg-memory-store.ts` | Align with IFixSessionStore interface |
168
+ | `src/transport/ascii/ascii-session.ts` | Integrate store lifecycle |
169
+ | `src/config/js-fix-config.ts` | Add SessionStoreFactory to config |
170
+
171
+ ---
172
+
173
+ ## Phase 5: Resend Request Improvements
174
+
175
+ **Priority: Medium | Risk: Low-Medium | Scope: Small**
176
+
177
+ ### Problem
178
+
179
+ The TS version sends a simple ResendRequest on gap detection with no protection against request storms or tracking of pending requests.
180
+
181
+ ### C# Solution
182
+
183
+ `ResendRequestManager` in the coordinator provides:
184
+ - Pending request tracking (`PendingResendRequests` collection)
185
+ - Storm protection — after N requests without response, accepts the gap
186
+ - Delayed message detection — clears pending requests when gap-filling messages arrive
187
+ - `ResendGapFillOnly` mode — sends GapFill instead of replaying stored messages (prevents duplicate executions)
188
+
189
+ ### TS Files to Modify
190
+
191
+ | File | Change |
192
+ |------|--------|
193
+ | New: `src/transport/session/resend-request-manager.ts` | Port manager |
194
+ | `src/transport/ascii/ascii-session.ts` | Integrate with gap detection |
195
+
196
+ ---
197
+
198
+ ## Phase 6: Message Generator / XML Parser (Future)
199
+
200
+ **Priority: Low | Risk: Medium | Scope: Large**
201
+
202
+ - C# uses nested types for groups (sub-types) in generated code
203
+ - QuickFix XML parser has improved design with better error tracking
204
+ - Nice to align for maintenance but not critical
205
+
206
+ ---
207
+
208
+ ## General Principles
209
+
210
+ 1. **Incremental PRs** — one phase at a time, smallest safe changes
211
+ 2. **Test first** — port test data and write failing tests before fixing
212
+ 3. **Maintain compatibility** — existing tests must continue to pass
213
+ 4. **Align code structure** — where reasonable, keep TS looking similar to C# for easier future maintenance
214
+ 5. **No big bang** — each phase should be independently mergeable and useful
@@ -0,0 +1,46 @@
1
+ 8=FIX.4.4|9=0000095|35=A|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=1|57=|52=20241013-14:03:55.006|98=0|108=30|141=Y|10=000|
2
+ 8=FIX.4.4|9=95|35=0|34=1|49=FIXSIMDEMO|52=20241013-14:04:31.878|56=sjames8888@gmail_com|112=0.824042533442398|10=088|
3
+ 8=FIX.4.4|9=0000111|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=2|57=|52=20241013-14:04:32.430|112=heartbeat-10/13/2024 14:04:32|10=248|
4
+ 8=FIX.4.4|9=0000111|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=3|57=|52=20241013-14:05:02.038|112=heartbeat-10/13/2024 14:05:02|10=249|
5
+ 8=FIX.4.4|9=0000111|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=4|57=|52=20241013-14:05:32.041|112=heartbeat-10/13/2024 14:05:32|10=250|
6
+ 8=FIX.4.4|9=0000111|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=5|57=|52=20241013-14:06:02.041|112=heartbeat-10/13/2024 14:06:02|10=247|
7
+ 8=FIX.4.4|9=151|35=6|34=2|49=FIXSIMDEMO|52=20241013-14:06:17.412|56=sjames8888@gmail_com|15=GBP|22=5|23=566638644251319700000|27=100|28=N|44=40|48=VOD.L|54=1|55=VOD.L|10=156|
8
+ 8=FIX.4.4|9=0000111|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=6|57=|52=20241013-14:06:32.037|112=heartbeat-10/13/2024 14:06:32|10=003|
9
+ 8=FIX.4.4|9=0000111|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=7|57=|52=20241013-14:07:02.042|112=heartbeat-10/13/2024 14:07:02|10=252|
10
+ 8=FIX.4.4|9=0000111|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=8|57=|52=20241013-14:07:32.029|112=heartbeat-10/13/2024 14:07:32|10=008|
11
+ 8=FIX.4.4|9=95|35=1|34=3|49=FIXSIMDEMO|52=20241013-14:07:35.444|56=sjames8888@gmail_com|112=0.349266975815067|10=104|
12
+ 8=FIX.4.4|9=0000099|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=9|57=|52=20241013-14:07:35.930|112=0.349266975815067|10=011|
13
+ 8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=10|57=|52=20241013-14:08:05.043|112=heartbeat-10/13/2024 14:08:05|10=048|
14
+ 8=FIX.4.4|9=141|35=V|34=4|49=FIXSIMDEMO|52=20241013-14:08:12.728|56=sjames8888@gmail_com|262=VOD.L|263=1|264=1|146=1|55=VOD.L|167=CS|267=3|269=0|269=1|269=2|10=128|
15
+ 8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=11|57=|52=20241013-14:08:35.030|112=heartbeat-10/13/2024 14:08:35|10=051|
16
+ 8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=12|57=|52=20241013-14:09:05.043|112=heartbeat-10/13/2024 14:09:05|10=052|
17
+ 8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=13|57=|52=20241013-14:09:35.037|112=heartbeat-10/13/2024 14:09:35|10=062|
18
+ 8=FIX.4.4|9=193|35=D|34=5|49=FIXSIMDEMO|52=20241013-14:09:45.126|56=sjames8888@gmail_com|11=567638644253361428000|15=GBP|21=2|22=5|38=100|40=2|44=100|48=VOD.L|54=1|55=VOD.L|59=0|60=20241013-14:09:45.126|388=1|10=091|
19
+ 8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=14|57=|52=20241013-14:10:05.041|112=heartbeat-10/13/2024 14:10:05|10=036|
20
+ 8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=15|57=|52=20241013-14:10:35.043|112=heartbeat-10/13/2024 14:10:35|10=045|
21
+ 8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=16|57=|52=20241013-14:11:05.038|112=heartbeat-10/13/2024 14:11:05|10=046|
22
+ 8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=17|57=|52=20241013-14:11:35.031|112=heartbeat-10/13/2024 14:11:35|10=046|
23
+ 8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=18|57=|52=20241013-14:12:05.041|112=heartbeat-10/13/2024 14:12:05|10=044|
24
+ 8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=19|57=|52=20241013-14:12:35.043|112=heartbeat-10/13/2024 14:12:35|10=053|
25
+ 8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=20|57=|52=20241013-14:13:05.028|112=heartbeat-10/13/2024 14:13:05|10=044|
26
+ 8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=21|57=|52=20241013-14:13:35.029|112=heartbeat-10/13/2024 14:13:35|10=052|
27
+ 8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=22|57=|52=20241013-14:14:05.041|112=heartbeat-10/13/2024 14:14:05|10=043|
28
+ 8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=23|57=|52=20241013-14:14:35.028|112=heartbeat-10/13/2024 14:14:35|10=055|
29
+ 8=FIX.4.4|9=261|35=8|34=6|49=FIXSIMDEMO|52=20241013-14:15:00.746|56=sjames8888@gmail_com|6=100|14=100|15=GBP|17=41638644256253512000|18=VOD.L|21=2|22=5|31=100|32=100|37=638644257007460000|38=100|39=2|40=2|44=100|48=VOD.L|54=1|55=VOD.L|59=0|60=20241013-14:15:00.746|150=2|151=0|10=207|
30
+ 8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=24|57=|52=20241013-14:15:05.030|112=heartbeat-10/13/2024 14:15:05|10=045|
31
+ 8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=25|57=|52=20241013-14:15:35.034|112=heartbeat-10/13/2024 14:15:35|10=056|
32
+ 8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=26|57=|52=20241013-14:16:05.033|112=heartbeat-10/13/2024 14:16:05|10=052|
33
+ 8=FIX.4.4|9=119|35=R|34=7|49=FIXSIMDEMO|52=20241013-14:16:23.036|56=sjames8888@gmail_com|131=569638644257643472000|146=1|55=VOD.L|54=1|10=113|
34
+ 8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=27|57=|52=20241013-14:16:35.037|112=heartbeat-10/13/2024 14:16:35|10=063|
35
+ 8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=28|57=|52=20241013-14:17:05.033|112=heartbeat-10/13/2024 14:17:05|10=056|
36
+ 8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=29|57=|52=20241013-14:17:35.038|112=heartbeat-10/13/2024 14:17:35|10=068|
37
+ 8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=30|57=|52=20241013-14:18:05.037|112=heartbeat-10/13/2024 14:18:05|10=055|
38
+ 8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=31|57=|52=20241013-14:18:35.029|112=heartbeat-10/13/2024 14:18:35|10=063|
39
+ 8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=32|57=|52=20241013-14:19:05.040|112=heartbeat-10/13/2024 14:19:05|10=053|
40
+ 8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=33|57=|52=20241013-14:19:35.029|112=heartbeat-10/13/2024 14:19:35|10=067|
41
+ 8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=34|57=|52=20241013-14:20:05.031|112=heartbeat-10/13/2024 14:20:05|10=039|
42
+ 8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=35|57=|52=20241013-14:20:35.029|112=heartbeat-10/13/2024 14:20:35|10=053|
43
+ 8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=36|57=|52=20241013-14:21:05.036|112=heartbeat-10/13/2024 14:21:05|10=048|
44
+ 8=FIX.4.4|9=0000112|35=0|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=37|57=|52=20241013-14:21:35.043|112=heartbeat-10/13/2024 14:21:35|10=053|
45
+ 8=FIX.4.4|9=0000095|35=A|49=sjames8888@gmail_com|56=FIXSIMDEMO|34=1|57=|52=20241013-14:31:31.938|98=0|108=30|141=Y|10=009|
46
+ 8=FIX.4.4|9=96|35=0|34=8|49=FIXSIMDEMO|52=20241013-14:31:36.182|56=sjames8888@gmail_com|112=0.0534090264949058|10=144|
@@ -0,0 +1,21 @@
1
+ {
2
+ "application": {
3
+ "type": "initiator",
4
+ "name": "test_client",
5
+ "tcp": {
6
+ "host": "localhost",
7
+ "port": 2344
8
+ },
9
+ "protocol": "ascii",
10
+ "dictionary": "data/FIX44.xml"
11
+ },
12
+ "Username": "",
13
+ "Password": "",
14
+ "EncryptMethod": 0,
15
+ "ResetSeqNumFlag": true,
16
+ "HeartBtInt": 30,
17
+ "SenderCompId": "sjames8888@gmail_com",
18
+ "TargetCompID": "FIXSIMDEMO",
19
+ "TargetSubID": "",
20
+ "BeginString": "FIX.4.4"
21
+ }
@@ -21,6 +21,7 @@ const tsyringe_1 = require("tsyringe");
21
21
  const di_tokens_1 = require("../../runtime/di-tokens");
22
22
  const segment_type_1 = require("../segment/segment-type");
23
23
  const ascii_segment_parser_error_1 = require("./ascii-segment-parser-error");
24
+ const tag_index_1 = require("./tag-index");
24
25
  let AsciiSegmentParser = class AsciiSegmentParser {
25
26
  constructor(definitions) {
26
27
  this.definitions = definitions;
@@ -34,6 +35,8 @@ let AsciiSegmentParser = class AsciiSegmentParser {
34
35
  const structureStack = [];
35
36
  let currentTagPosition = 0;
36
37
  let peek;
38
+ const exitedDepth1Components = new Set();
39
+ const fragmentedComponents = new Set();
37
40
  function unwind(tag) {
38
41
  var _a;
39
42
  while (structureStack.length > 1) {
@@ -42,6 +45,9 @@ let AsciiSegmentParser = class AsciiSegmentParser {
42
45
  continue;
43
46
  done.end(segments.length, currentTagPosition - 1, tags.tagPos[currentTagPosition - 1].tag);
44
47
  segments.push(done);
48
+ if (done.depth === 1 && done.name) {
49
+ exitedDepth1Components.add(done.name);
50
+ }
45
51
  peek = structureStack[structureStack.length - 1];
46
52
  if ((_a = peek.set) === null || _a === void 0 ? void 0 : _a.containedTag[tag]) {
47
53
  break;
@@ -78,6 +84,9 @@ let AsciiSegmentParser = class AsciiSegmentParser {
78
84
  }
79
85
  case contained_1.ContainedFieldType.Component: {
80
86
  const cf = currentField;
87
+ if (structureStack.length === 1 && exitedDepth1Components.has(cf.name)) {
88
+ fragmentedComponents.add(cf.name);
89
+ }
81
90
  structure = new segment_description_1.SegmentDescription(cf.name, tag, cf.definition, currentTagPosition, structureStack.length, segment_type_1.SegmentType.Component);
82
91
  break;
83
92
  }
@@ -150,10 +159,37 @@ let AsciiSegmentParser = class AsciiSegmentParser {
150
159
  segments[m1] = segments[m2];
151
160
  segments[m2] = tmp;
152
161
  }
162
+ function fragments() {
163
+ if (fragmentedComponents.size === 0)
164
+ return;
165
+ const ti = new tag_index_1.TagIndex(msgDefinition, tags, last + 1);
166
+ const seen = new Set();
167
+ for (let i = 1; i < segments.length - 1; i++) {
168
+ const seg = segments[i];
169
+ if (seg.depth !== 1)
170
+ continue;
171
+ if (!seg.name)
172
+ continue;
173
+ if (seg.segmentView)
174
+ continue;
175
+ if (seen.has(seg.name))
176
+ continue;
177
+ if (!fragmentedComponents.has(seg.name))
178
+ continue;
179
+ if (ti.isComponentGroupWrapper(seg.name))
180
+ continue;
181
+ const v = ti.getInstance(seg.name);
182
+ if (!v)
183
+ continue;
184
+ seen.add(seg.name);
185
+ seg.addSegmentView(v);
186
+ }
187
+ }
153
188
  const msgStructure = new segment_description_1.SegmentDescription(msgDefinition.name, tags.tagPos[0].tag, msgDefinition, currentTagPosition, structureStack.length, segment_type_1.SegmentType.Msg);
154
189
  structureStack.push(msgStructure);
155
190
  discover();
156
191
  clean();
192
+ fragments();
157
193
  return new structure_1.Structure(tags, segments);
158
194
  }
159
195
  };
@@ -1 +1 @@
1
- {"version":3,"file":"ascii-segment-parser.js","sourceRoot":"","sources":["../../../src/buffer/ascii/ascii-segment-parser.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,wEAAmE;AACnE,4CAAwC;AAExC,4DAGoC;AACpC,0DAKmC;AACnC,uCAA6C;AAC7C,uDAAkD;AAClD,0DAAqD;AACrD,6EAA+D;AAOxD,IAAM,kBAAkB,GAAxB,MAAM,kBAAkB;IAC7B,YAA2D,WAA2B;QAA3B,gBAAW,GAAX,WAAW,CAAgB;IACtF,CAAC;IAEM,KAAK,CAAE,OAAe,EAAE,IAAU,EAAE,IAAY;QAErD,MAAM,QAAQ,GAAyB,EAAE,CAAA;QACzC,MAAM,aAAa,GAAkC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;QAC1F,IAAI,CAAC,aAAa,EAAE,CAAC;YACnB,OAAO,IAAI,CAAA;QACb,CAAC;QAID,MAAM,cAAc,GAAyB,EAAE,CAAA;QAC/C,IAAI,kBAAkB,GAAW,CAAC,CAAA;QAClC,IAAI,IAAwB,CAAA;QAG5B,SAAS,MAAM,CAAE,GAAW;;YAC1B,OAAO,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACjC,MAAM,IAAI,GAAG,cAAc,CAAC,GAAG,EAAE,CAAA;gBACjC,IAAI,CAAC,IAAI;oBAAE,SAAQ;gBACnB,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,kBAAkB,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,kBAAkB,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;gBAC1F,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;gBACnB,IAAI,GAAG,cAAc,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;gBAChD,IAAI,MAAA,IAAI,CAAC,GAAG,0CAAE,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC;oBAEhC,MAAK;gBACP,CAAC;gBACD,IAAI,IAAI,CAAC,IAAI,KAAK,0BAAW,CAAC,GAAG,EAAE,CAAC;oBAElC,MAAK;gBACP,CAAC;YACH,CAAC;QACH,CAAC;QAED,SAAS,SAAS;YAChB,OAAkC;gBAChC,OAAO;gBACP,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,MAAM;gBACzB,IAAI;gBACJ,aAAa,EAAE,aAAa,aAAb,aAAa,uBAAb,aAAa,CAAE,QAAQ,EAAE;gBACxC,kBAAkB;gBAClB,IAAI,EAAE,IAAI,CAAC,QAAQ,EAAE;gBACrB,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;gBACzC,cAAc,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;aACtD,CAAA;QACH,CAAC;QAED,SAAS,OAAO,CAAE,GAAW;YAC3B,IAAI,SAAS,GAA8B,IAAI,CAAA;YAC/C,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,CAAA;YACtC,IAAI,CAAC,YAAY;gBAAE,OAAO,IAAI,CAAA;YAC9B,QAAQ,YAAY,CAAC,IAAI,EAAE,CAAC;gBAC1B,KAAK,8BAAkB,CAAC,MAAM,CAAC,CAAC,CAAC;oBAC/B,MAAM,EAAE,GAAyB,YAAoC,CAAA;oBACrE,IAAI,EAAE,CAAC,UAAU,CAAC,GAAG,KAAK,GAAG,EAAE,CAAC;wBAC9B,kBAAkB,GAAG,kBAAkB,GAAG,CAAC,CAAA;oBAC7C,CAAC;oBACD,MAAK;gBACP,CAAC;gBAED,KAAK,8BAAkB,CAAC,SAAS,CAAC,CAAC,CAAC;oBAClC,MAAM,EAAE,GAA4B,YAAuC,CAAA;oBAC3E,SAAS,GAAG,IAAI,wCAAkB,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,UAAU,EAC5D,kBAAkB,EAAE,cAAc,CAAC,MAAM,EAAE,0BAAW,CAAC,SAAS,CAAC,CAAA;oBACnE,MAAK;gBACP,CAAC;gBAED,KAAK,8BAAkB,CAAC,KAAK,CAAC,CAAC,CAAC;oBAC9B,MAAM,EAAE,GAA4B,YAAmC,CAAA;oBACvE,SAAS,GAAG,IAAI,wCAAkB,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,EAAE,CAAC,UAAU,EAC5D,kBAAkB,EAAE,cAAc,CAAC,MAAM,EAAE,0BAAW,CAAC,KAAK,CAAC,CAAA;oBAC/D,kBAAkB,GAAG,kBAAkB,GAAG,CAAC,CAAA;oBAC3C,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,GAAG,CAAC,CAAA;oBACzD,MAAK;gBACP,CAAC;gBAED,OAAO,CAAC,CAAC,CAAC;oBACR,MAAM,CAAC,GAAG,SAAS,EAAE,CAAA;oBACrB,MAAM,IAAI,6CAAgB,CAAC,kCAAkC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAA;gBACxE,CAAC;YACH,CAAC;YACD,OAAO,SAAS,CAAA;QAClB,CAAC;QAED,SAAS,cAAc,CAAE,GAAW;YAClC,IAAI,SAAS,GAAY,KAAK,CAAA;YAC9B,IAAI,GAAG,KAAK,IAAI,CAAC,YAAY,EAAE,CAAC;gBAC9B,IAAI,CAAC,oBAAoB,CAAC,kBAAkB,CAAC,CAAA;YAC/C,CAAC;iBAAM,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAGrC,SAAS,GAAG,cAAc,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,iBAAiB,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAA;YAClG,CAAC;YACD,OAAO,SAAS,CAAA;QAClB,CAAC;QAED,SAAS,GAAG,CAAE,GAAW;YACvB,MAAM,GAAG,GAAG,IAAI,wCAAkB,CAAC,YAAY,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,EAC5D,kBAAkB,EAAE,cAAc,CAAC,MAAM,EAAE,0BAAW,CAAC,GAAG,CAAC,CAAA;YAC7D,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,kBAAkB,EAAE,GAAG,CAAC,CAAA;YACjD,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;YAClB,kBAAkB,EAAE,CAAA;QACtB,CAAC;QAED,SAAS,QAAQ;;YACf,OAAO,kBAAkB,IAAI,IAAI,EAAE,CAAC;gBAClC,MAAM,GAAG,GAAW,IAAI,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,GAAG,CAAA;gBACvD,IAAI,GAAG,cAAc,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;gBAChD,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,CAAA;gBACzB,IAAI,CAAC,CAAA,MAAA,IAAI,CAAC,GAAG,0CAAE,YAAY,CAAC,GAAG,CAAC,CAAA,IAAI,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC;oBAExD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,KAAK,0BAAW,CAAC,GAAG,CAAA;oBAC7C,IAAI,OAAO,EAAE,CAAC;wBACZ,GAAG,CAAC,GAAG,CAAC,CAAA;oBACV,CAAC;yBAAM,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBAErC,MAAM,CAAC,GAAG,CAAC,CAAA;oBACb,CAAC;oBACD,SAAQ;gBACV,CAAC;gBACD,IAAI,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;oBACpC,MAAM,IAAI,6CAAgB,CAAC,6CAA6C,GAAG,EAAE,EAAE,SAAS,EAAE,CAAC,CAAA;gBAC7F,CAAC;gBACD,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,CAAA;gBAC9B,IAAI,SAAS,EAAE,CAAC;oBACd,cAAc,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;gBAChC,CAAC;YACH,CAAC;QACH,CAAC;QAED,SAAS,KAAK;YAEZ,OAAO,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACjC,MAAM,IAAI,GAAG,cAAc,CAAC,GAAG,EAAE,CAAA;gBACjC,IAAI,CAAC,IAAI;oBAAE,SAAQ;gBACnB,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,EAAE,kBAAkB,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,kBAAkB,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;gBAC1F,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,IAAI,CAAA;YAClC,CAAC;YAED,MAAM,EAAE,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAA;YAC9B,MAAM,EAAE,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAA;YAC9B,MAAM,GAAG,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAA;YACxB,QAAQ,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAA;YAC3B,QAAQ,CAAC,EAAE,CAAC,GAAG,GAAG,CAAA;QACpB,CAAC;QAED,MAAM,YAAY,GAAG,IAAI,wCAAkB,CAAC,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,aAAa,EAC/F,kBAAkB,EAAE,cAAc,CAAC,MAAM,EAAE,0BAAW,CAAC,GAAG,CAAC,CAAA;QAC7D,cAAc,CAAC,IAAI,CAAC,YAAY,CAAC,CAAA;QACjC,QAAQ,EAAE,CAAA;QACV,KAAK,EAAE,CAAA;QAGP,OAAO,IAAI,qBAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAA;IACtC,CAAC;CACF,CAAA;AA9JY,gDAAkB;6BAAlB,kBAAkB;IAD9B,IAAA,qBAAU,GAAE;IAEG,WAAA,IAAA,iBAAM,EAAC,oBAAQ,CAAC,WAAW,CAAC,CAAA;qCAA8B,2BAAc;GAD3E,kBAAkB,CA8J9B","sourcesContent":["import { SegmentDescription } from '../segment/segment-description'\nimport { Structure } from '../structure'\nimport { Tags } from '../tag/tags'\nimport {\n FixDefinitions,\n MessageDefinition\n} from '../../dictionary/definition'\nimport {\n ContainedComponentField,\n ContainedGroupField,\n ContainedSimpleField,\n ContainedFieldType\n} from '../../dictionary/contained'\nimport { inject, injectable } from 'tsyringe'\nimport { DITokens } from '../../runtime/di-tokens'\nimport { SegmentType } from '../segment/segment-type'\nimport { AsciiParserError } from './ascii-segment-parser-error'\nimport { AsciiSegmentParserSummary } from './ascii-segment-parser-summary'\n\n// this takes linear time i.e. it constantly makes forward progress\n// one tag at a time\n\n@injectable()\nexport class AsciiSegmentParser {\n constructor (@inject(DITokens.Definitions) public readonly definitions: FixDefinitions) {\n }\n\n public parse (msgType: string, tags: Tags, last: number): Structure | null {\n // completed segments in that they are fully parsed\n const segments: SegmentDescription[] = []\n const msgDefinition: MessageDefinition | undefined = this.definitions.message.get(msgType)\n if (!msgDefinition) {\n return null\n }\n // in process of being discovered and may have any amount of depth\n // i.e. a component containing a repeated group of components\n // with sub-groups of components\n const structureStack: SegmentDescription[] = []\n let currentTagPosition: number = 0\n let peek: SegmentDescription\n\n // having finished one segments keep unwinding until tag matches further up stack\n function unwind (tag: number): void {\n while (structureStack.length > 1) {\n const done = structureStack.pop()\n if (!done) continue\n done.end(segments.length, currentTagPosition - 1, tags.tagPos[currentTagPosition - 1].tag)\n segments.push(done)\n peek = structureStack[structureStack.length - 1]\n if (peek.set?.containedTag[tag]) {\n // unwound to point this tag lives in this set.\n break\n }\n if (peek.type === SegmentType.Msg) {\n // this is unknown tag and it is not part of trailer so raise unknown\n break\n }\n }\n }\n\n function summarise (): AsciiSegmentParserSummary {\n return <AsciiSegmentParserSummary>{\n msgType,\n tags: tags.clone().tagPos,\n last,\n msgDefinition: msgDefinition?.toString(),\n currentTagPosition,\n peek: peek.toString(),\n segments: segments.map(s => s.toString()),\n structureStack: structureStack.map(s => s.toString())\n }\n }\n\n function examine (tag: number): SegmentDescription | null {\n let structure: SegmentDescription | null = null\n const currentField = peek.currentField\n if (!currentField) return null\n switch (currentField.type) {\n case ContainedFieldType.Simple: {\n const sf: ContainedSimpleField = currentField as ContainedSimpleField\n if (sf.definition.tag === tag) {\n currentTagPosition = currentTagPosition + 1\n }\n break\n }\n // moving deeper into structure, start a new context\n case ContainedFieldType.Component: {\n const cf: ContainedComponentField = currentField as ContainedComponentField\n structure = new SegmentDescription(cf.name, tag, cf.definition,\n currentTagPosition, structureStack.length, SegmentType.Component)\n break\n }\n // for a group also need to know where all delimiters are positioned\n case ContainedFieldType.Group: {\n const gf: ContainedComponentField = currentField as ContainedGroupField\n structure = new SegmentDescription(gf.name, tag, gf.definition,\n currentTagPosition, structureStack.length, SegmentType.Group)\n currentTagPosition = currentTagPosition + 1\n structure.startGroup(tags.tagPos[currentTagPosition].tag)\n break\n }\n\n default: {\n const c = summarise()\n throw new AsciiParserError(`examine unknown type for tag = ${tag}`, c)\n }\n }\n return structure\n }\n\n function groupDelimiter (tag: number): boolean {\n let delimiter: boolean = false\n if (tag === peek.delimiterTag) {\n peek.addDelimiterPosition(currentTagPosition)\n } else if (structureStack.length > 1) {\n // if a group is represented by a repeated component, then the tag representing delimiter\n // needs to be added further up stack to group itself.\n delimiter = structureStack[structureStack.length - 2].groupAddDelimiter(tag, currentTagPosition)\n }\n return delimiter\n }\n\n function gap (tag: number): void {\n const gap = new SegmentDescription('.undefined', tag, peek.set,\n currentTagPosition, structureStack.length, SegmentType.Gap)\n gap.end(segments.length, currentTagPosition, tag)\n segments.push(gap)\n currentTagPosition++\n }\n\n function discover (): void {\n while (currentTagPosition <= last) {\n const tag: number = tags.tagPos[currentTagPosition].tag\n peek = structureStack[structureStack.length - 1]\n peek.setCurrentField(tag)\n if (!peek.set?.containedTag[tag] || groupDelimiter(tag)) {\n // unravelled all way back to root hence this is not recognised\n const unknown = peek.type === SegmentType.Msg\n if (unknown) {\n gap(tag)\n } else if (structureStack.length > 1) {\n // move back up the segments and save the finished group / component\n unwind(tag)\n }\n continue\n }\n if (!peek.currentField || !peek.set) {\n throw new AsciiParserError(`discover no currentField or set for tag = ${tag}`, summarise())\n }\n const structure = examine(tag)\n if (structure) {\n structureStack.push(structure)\n }\n }\n }\n\n function clean (): void {\n // any remainder components can be closed.\n while (structureStack.length > 0) {\n const done = structureStack.pop()\n if (!done) continue\n done.end(segments.length, currentTagPosition - 1, tags.tagPos[currentTagPosition - 1].tag)\n segments[segments.length] = done\n }\n // logically reverse the trailer and message so trailer is last in list.\n const m1 = segments.length - 1\n const m2 = segments.length - 2\n const tmp = segments[m1]\n segments[m1] = segments[m2]\n segments[m2] = tmp\n }\n\n const msgStructure = new SegmentDescription(msgDefinition.name, tags.tagPos[0].tag, msgDefinition,\n currentTagPosition, structureStack.length, SegmentType.Msg)\n structureStack.push(msgStructure)\n discover()\n clean()\n\n // now know where all components and groups are positioned within message\n return new Structure(tags, segments)\n }\n}\n"]}
1
+ {"version":3,"file":"ascii-segment-parser.js","sourceRoot":"","sources":["../../../src/buffer/ascii/ascii-segment-parser.ts"],"names":[],"mappings":"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","sourcesContent":["import { SegmentDescription } from '../segment/segment-description'\nimport { Structure } from '../structure'\nimport { Tags } from '../tag/tags'\nimport {\n FixDefinitions,\n MessageDefinition\n} from '../../dictionary/definition'\nimport {\n ContainedComponentField,\n ContainedGroupField,\n ContainedSimpleField,\n ContainedFieldType\n} from '../../dictionary/contained'\nimport { inject, injectable } from 'tsyringe'\nimport { DITokens } from '../../runtime/di-tokens'\nimport { SegmentType } from '../segment/segment-type'\nimport { AsciiParserError } from './ascii-segment-parser-error'\nimport { AsciiSegmentParserSummary } from './ascii-segment-parser-summary'\nimport { TagIndex } from './tag-index'\n\n// this takes linear time i.e. it constantly makes forward progress\n// one tag at a time\n\n@injectable()\nexport class AsciiSegmentParser {\n constructor (@inject(DITokens.Definitions) public readonly definitions: FixDefinitions) {\n }\n\n public parse (msgType: string, tags: Tags, last: number): Structure | null {\n // completed segments in that they are fully parsed\n const segments: SegmentDescription[] = []\n const msgDefinition: MessageDefinition | undefined = this.definitions.message.get(msgType)\n if (!msgDefinition) {\n return null\n }\n // in process of being discovered and may have any amount of depth\n // i.e. a component containing a repeated group of components\n // with sub-groups of components\n const structureStack: SegmentDescription[] = []\n let currentTagPosition: number = 0\n let peek: SegmentDescription\n\n // track depth-1 components that have been exited for fragmentation detection\n const exitedDepth1Components: Set<string> = new Set()\n const fragmentedComponents: Set<string> = new Set()\n\n // having finished one segments keep unwinding until tag matches further up stack\n function unwind (tag: number): void {\n while (structureStack.length > 1) {\n const done = structureStack.pop()\n if (!done) continue\n done.end(segments.length, currentTagPosition - 1, tags.tagPos[currentTagPosition - 1].tag)\n segments.push(done)\n\n // track when we exit depth-1 components for fragmentation detection\n if (done.depth === 1 && done.name) {\n exitedDepth1Components.add(done.name)\n }\n\n peek = structureStack[structureStack.length - 1]\n if (peek.set?.containedTag[tag]) {\n // unwound to point this tag lives in this set.\n break\n }\n if (peek.type === SegmentType.Msg) {\n // this is unknown tag and it is not part of trailer so raise unknown\n break\n }\n }\n }\n\n function summarise (): AsciiSegmentParserSummary {\n return <AsciiSegmentParserSummary>{\n msgType,\n tags: tags.clone().tagPos,\n last,\n msgDefinition: msgDefinition?.toString(),\n currentTagPosition,\n peek: peek.toString(),\n segments: segments.map(s => s.toString()),\n structureStack: structureStack.map(s => s.toString())\n }\n }\n\n function examine (tag: number): SegmentDescription | null {\n let structure: SegmentDescription | null = null\n const currentField = peek.currentField\n if (!currentField) return null\n switch (currentField.type) {\n case ContainedFieldType.Simple: {\n const sf: ContainedSimpleField = currentField as ContainedSimpleField\n if (sf.definition.tag === tag) {\n currentTagPosition = currentTagPosition + 1\n }\n break\n }\n // moving deeper into structure, start a new context\n case ContainedFieldType.Component: {\n const cf: ContainedComponentField = currentField as ContainedComponentField\n // detect fragmentation: re-entering a depth-1 component we already exited\n if (structureStack.length === 1 && exitedDepth1Components.has(cf.name)) {\n fragmentedComponents.add(cf.name)\n }\n structure = new SegmentDescription(cf.name, tag, cf.definition,\n currentTagPosition, structureStack.length, SegmentType.Component)\n break\n }\n // for a group also need to know where all delimiters are positioned\n case ContainedFieldType.Group: {\n const gf: ContainedComponentField = currentField as ContainedGroupField\n structure = new SegmentDescription(gf.name, tag, gf.definition,\n currentTagPosition, structureStack.length, SegmentType.Group)\n currentTagPosition = currentTagPosition + 1\n structure.startGroup(tags.tagPos[currentTagPosition].tag)\n break\n }\n\n default: {\n const c = summarise()\n throw new AsciiParserError(`examine unknown type for tag = ${tag}`, c)\n }\n }\n return structure\n }\n\n function groupDelimiter (tag: number): boolean {\n let delimiter: boolean = false\n if (tag === peek.delimiterTag) {\n peek.addDelimiterPosition(currentTagPosition)\n } else if (structureStack.length > 1) {\n // if a group is represented by a repeated component, then the tag representing delimiter\n // needs to be added further up stack to group itself.\n delimiter = structureStack[structureStack.length - 2].groupAddDelimiter(tag, currentTagPosition)\n }\n return delimiter\n }\n\n function gap (tag: number): void {\n const gap = new SegmentDescription('.undefined', tag, peek.set,\n currentTagPosition, structureStack.length, SegmentType.Gap)\n gap.end(segments.length, currentTagPosition, tag)\n segments.push(gap)\n currentTagPosition++\n }\n\n function discover (): void {\n while (currentTagPosition <= last) {\n const tag: number = tags.tagPos[currentTagPosition].tag\n peek = structureStack[structureStack.length - 1]\n peek.setCurrentField(tag)\n if (!peek.set?.containedTag[tag] || groupDelimiter(tag)) {\n // unravelled all way back to root hence this is not recognised\n const unknown = peek.type === SegmentType.Msg\n if (unknown) {\n gap(tag)\n } else if (structureStack.length > 1) {\n // move back up the segments and save the finished group / component\n unwind(tag)\n }\n continue\n }\n if (!peek.currentField || !peek.set) {\n throw new AsciiParserError(`discover no currentField or set for tag = ${tag}`, summarise())\n }\n const structure = examine(tag)\n if (structure) {\n structureStack.push(structure)\n }\n }\n }\n\n function clean (): void {\n // any remainder components can be closed.\n while (structureStack.length > 0) {\n const done = structureStack.pop()\n if (!done) continue\n done.end(segments.length, currentTagPosition - 1, tags.tagPos[currentTagPosition - 1].tag)\n segments[segments.length] = done\n }\n // logically reverse the trailer and message so trailer is last in list.\n const m1 = segments.length - 1\n const m2 = segments.length - 2\n const tmp = segments[m1]\n segments[m1] = segments[m2]\n segments[m2] = tmp\n }\n\n function fragments (): void {\n // only build SegmentViews for components detected as fragmented during discover\n // non-fragmented components use their position ranges directly (zero overhead)\n if (fragmentedComponents.size === 0) return\n const ti = new TagIndex(msgDefinition!, tags, last + 1)\n const seen: Set<string> = new Set()\n for (let i = 1; i < segments.length - 1; i++) {\n const seg = segments[i]\n if (seg.depth !== 1) continue\n if (!seg.name) continue\n if (seg.segmentView) continue\n if (seen.has(seg.name)) continue\n if (!fragmentedComponents.has(seg.name)) continue\n if (ti.isComponentGroupWrapper(seg.name)) continue\n const v = ti.getInstance(seg.name)\n if (!v) continue\n seen.add(seg.name)\n seg.addSegmentView(v)\n }\n }\n\n const msgStructure = new SegmentDescription(msgDefinition.name, tags.tagPos[0].tag, msgDefinition,\n currentTagPosition, structureStack.length, SegmentType.Msg)\n structureStack.push(msgStructure)\n discover()\n clean()\n fragments()\n\n // now know where all components and groups are positioned within message\n return new Structure(tags, segments)\n }\n}\n"]}
@@ -0,0 +1,20 @@
1
+ import { IContainedSet } from '../../dictionary/contained';
2
+ import { SegmentView } from '../segment/segment-view';
3
+ import { Tags } from '../tag/tags';
4
+ export interface TagSpan {
5
+ start: number;
6
+ end: number;
7
+ }
8
+ export declare class TagIndex {
9
+ readonly set: IContainedSet;
10
+ private readonly sortedTagPos;
11
+ private readonly tagSpans;
12
+ private readonly componentGroupWrappers;
13
+ private readonly cache;
14
+ constructor(set: IContainedSet, tags: Tags, count: number);
15
+ private populateTagSpans;
16
+ private calcGroups;
17
+ private findParentComponent;
18
+ getInstance(name: string): SegmentView | null;
19
+ isComponentGroupWrapper(name: string): boolean;
20
+ }
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TagIndex = void 0;
4
+ const segment_view_1 = require("../segment/segment-view");
5
+ const tag_pos_1 = require("../tag/tag-pos");
6
+ class TagIndex {
7
+ constructor(set, tags, count) {
8
+ this.set = set;
9
+ this.tagSpans = new Map();
10
+ this.componentGroupWrappers = new Set();
11
+ this.cache = new Map();
12
+ this.sortedTagPos = new Array(count);
13
+ for (let i = 0; i < count; i++) {
14
+ this.sortedTagPos[i] = tags.tagPos[i];
15
+ }
16
+ this.sortedTagPos.sort(tag_pos_1.TagPos.compare);
17
+ this.populateTagSpans();
18
+ this.calcGroups(tags, count);
19
+ }
20
+ populateTagSpans() {
21
+ for (let i = 0; i < this.sortedTagPos.length; i++) {
22
+ const t = this.sortedTagPos[i];
23
+ const existing = this.tagSpans.get(t.tag);
24
+ if (existing) {
25
+ existing.end = i;
26
+ }
27
+ else {
28
+ this.tagSpans.set(t.tag, { start: i, end: i });
29
+ }
30
+ }
31
+ }
32
+ calcGroups(tags, count) {
33
+ for (let i = 0; i < count; i++) {
34
+ const tag = tags.tagPos[i];
35
+ const field = this.set.tagToField[tag.tag];
36
+ if (!field)
37
+ continue;
38
+ const component = this.findParentComponent(tag.tag);
39
+ if (component) {
40
+ const componentSet = this.set.components.get(component);
41
+ if (componentSet && componentSet.fields.length === 1) {
42
+ this.componentGroupWrappers.add(component);
43
+ }
44
+ }
45
+ }
46
+ }
47
+ findParentComponent(tag) {
48
+ for (const [name, componentSet] of this.set.components) {
49
+ if (componentSet.containedTag[tag]) {
50
+ return name;
51
+ }
52
+ }
53
+ return null;
54
+ }
55
+ getInstance(name) {
56
+ const cached = this.cache.get(name);
57
+ if (cached !== undefined) {
58
+ return cached;
59
+ }
60
+ const componentSet = this.set.components.get(name);
61
+ if (!componentSet) {
62
+ this.cache.set(name, null);
63
+ return null;
64
+ }
65
+ const view = new segment_view_1.SegmentView(name, componentSet);
66
+ const flatTags = componentSet.flattenedTag;
67
+ for (let x = 0; x < flatTags.length; x++) {
68
+ const t = flatTags[x];
69
+ const span = this.tagSpans.get(t);
70
+ if (!span)
71
+ continue;
72
+ if (span.start === span.end) {
73
+ view.add(this.sortedTagPos[span.start]);
74
+ }
75
+ else {
76
+ for (let j = span.start; j <= span.end; j++) {
77
+ view.add(this.sortedTagPos[j]);
78
+ }
79
+ }
80
+ }
81
+ this.cache.set(name, view);
82
+ return view;
83
+ }
84
+ isComponentGroupWrapper(name) {
85
+ return this.componentGroupWrappers.has(name);
86
+ }
87
+ }
88
+ exports.TagIndex = TagIndex;
89
+ //# sourceMappingURL=tag-index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tag-index.js","sourceRoot":"","sources":["../../../src/buffer/ascii/tag-index.ts"],"names":[],"mappings":"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","sourcesContent":["import { IContainedSet } from '../../dictionary/contained'\nimport { SegmentView } from '../segment/segment-view'\nimport { TagPos } from '../tag/tag-pos'\nimport { Tags } from '../tag/tags'\n\nexport interface TagSpan {\n start: number\n end: number\n}\n\nexport class TagIndex {\n private readonly sortedTagPos: TagPos[]\n private readonly tagSpans: Map<number, TagSpan> = new Map()\n private readonly componentGroupWrappers: Set<string> = new Set()\n private readonly cache: Map<string, SegmentView | null> = new Map()\n\n constructor (\n public readonly set: IContainedSet,\n tags: Tags,\n count: number) {\n this.sortedTagPos = new Array(count)\n for (let i = 0; i < count; i++) {\n this.sortedTagPos[i] = tags.tagPos[i]\n }\n this.sortedTagPos.sort(TagPos.compare)\n this.populateTagSpans()\n this.calcGroups(tags, count)\n }\n\n private populateTagSpans (): void {\n for (let i = 0; i < this.sortedTagPos.length; i++) {\n const t = this.sortedTagPos[i]\n const existing = this.tagSpans.get(t.tag)\n if (existing) {\n existing.end = i\n } else {\n this.tagSpans.set(t.tag, { start: i, end: i })\n }\n }\n }\n\n private calcGroups (tags: Tags, count: number): void {\n for (let i = 0; i < count; i++) {\n const tag = tags.tagPos[i]\n const field = this.set.tagToField[tag.tag]\n if (!field) continue\n // detect component group wrappers (single-field components containing a group)\n const component = this.findParentComponent(tag.tag)\n if (component) {\n const componentSet = this.set.components.get(component)\n if (componentSet && componentSet.fields.length === 1) {\n this.componentGroupWrappers.add(component)\n }\n }\n }\n }\n\n private findParentComponent (tag: number): string | null {\n for (const [name, componentSet] of this.set.components) {\n if (componentSet.containedTag[tag]) {\n return name\n }\n }\n return null\n }\n\n public getInstance (name: string): SegmentView | null {\n const cached = this.cache.get(name)\n if (cached !== undefined) {\n return cached\n }\n\n const componentSet = this.set.components.get(name)\n if (!componentSet) {\n this.cache.set(name, null)\n return null\n }\n\n const view = new SegmentView(name, componentSet)\n const flatTags = componentSet.flattenedTag\n for (let x = 0; x < flatTags.length; x++) {\n const t = flatTags[x]\n const span = this.tagSpans.get(t)\n if (!span) continue\n if (span.start === span.end) {\n view.add(this.sortedTagPos[span.start])\n } else {\n for (let j = span.start; j <= span.end; j++) {\n view.add(this.sortedTagPos[j])\n }\n }\n }\n\n this.cache.set(name, view)\n return view\n }\n\n public isComponentGroupWrapper (name: string): boolean {\n return this.componentGroupWrappers.has(name)\n }\n}\n"]}
@@ -234,8 +234,15 @@ class MsgView {
234
234
  allStrings() {
235
235
  const segment = this.segment;
236
236
  const range = [];
237
- for (let i = segment.startPosition; i <= segment.endPosition; ++i) {
238
- range[range.length] = i;
237
+ if (segment.segmentView) {
238
+ for (const tp of segment.segmentView.tags) {
239
+ range[range.length] = tp.position;
240
+ }
241
+ }
242
+ else {
243
+ for (let i = segment.startPosition; i <= segment.endPosition; ++i) {
244
+ range[range.length] = i;
245
+ }
239
246
  }
240
247
  return range.map((i) => this.stringAtPosition(i));
241
248
  }
@@ -334,8 +341,14 @@ class MsgView {
334
341
  let forwards = this.sortedTagPosForwards;
335
342
  if (!forwards) {
336
343
  const segment = this.segment;
337
- forwards = this.sortedTagPosForwards = this.structure.tags.tagPos.slice(segment.startPosition, segment.endPosition + 1);
338
- forwards.sort(tag_pos_1.TagPos.compare);
344
+ if (segment.segmentView) {
345
+ forwards = this.sortedTagPosForwards = segment.segmentView.tags.slice();
346
+ forwards.sort(tag_pos_1.TagPos.compare);
347
+ }
348
+ else {
349
+ forwards = this.sortedTagPosForwards = this.structure.tags.tagPos.slice(segment.startPosition, segment.endPosition + 1);
350
+ forwards.sort(tag_pos_1.TagPos.compare);
351
+ }
339
352
  this.sortedTagPosBackwards = forwards.slice().reverse();
340
353
  }
341
354
  return tag_pos_1.TagPos.binarySearch(forwards, tag);