@@ -52,6 +52,14 @@ export type JSONValue =
52
52
| { + [ key : string ] : JSONValue }
53
53
| $ReadOnlyArray < JSONValue > ;
54
54
55
+ const ROW_ID = 0 ;
56
+ const ROW_TAG = 1 ;
57
+ const ROW_LENGTH = 2 ;
58
+ const ROW_CHUNK_BY_NEWLINE = 3 ;
59
+ const ROW_CHUNK_BY_LENGTH = 4 ;
60
+
61
+ type RowParserState = 0 | 1 | 2 | 3 | 4 ;
62
+
55
63
const PENDING = 'pending' ;
56
64
const BLOCKED = 'blocked' ;
57
65
const RESOLVED_MODEL = 'resolved_model' ;
@@ -165,9 +173,13 @@ export type Response = {
165
173
_bundlerConfig : SSRManifest ,
166
174
_callServer : CallServerCallback ,
167
175
_chunks : Map < number , SomeChunk< any >> ,
168
- _partialRow : string ,
169
176
_fromJSON : ( key : string , value : JSONValue ) => any ,
170
177
_stringDecoder : StringDecoder ,
178
+ _rowState : RowParserState ,
179
+ _rowID : number , // parts of a row ID parsed so far
180
+ _rowTag : number , // 0 indicates that we're currently parsing the row ID
181
+ _rowLength : number , // remaining bytes in the row. 0 indicates that we're looking for a newline.
182
+ _buffer : Array < string | Uint8Array > , // chunks received so far as part of this row
171
183
} ;
172
184
173
185
function readChunk < T > (chunk: SomeChunk< T > ): T {
@@ -665,9 +677,13 @@ export function createResponse(
665
677
_bundlerConfig : bundlerConfig ,
666
678
_callServer : callServer !== undefined ? callServer : missingCall ,
667
679
_chunks : chunks ,
668
- _partialRow : '' ,
669
680
_stringDecoder : createStringDecoder ( ) ,
670
681
_fromJSON : ( null : any ) ,
682
+ _rowState : 0 ,
683
+ _rowID : 0 ,
684
+ _rowTag : 0 ,
685
+ _rowLength : 0 ,
686
+ _buffer : [ ] ,
671
687
} ;
672
688
// Don't inline this call because it causes closure to outline the call above.
673
689
response . _fromJSON = createFromJSONCallback ( response ) ;
@@ -806,29 +822,40 @@ function resolveHint(
806
822
dispatchHint ( code , hintModel ) ;
807
823
}
808
824
809
- function processFullRow ( response : Response , row : string ) : void {
810
- if ( row === '' ) {
811
- return ;
825
+ function processFullRow (
826
+ response : Response ,
827
+ id : number ,
828
+ tag : number ,
829
+ buffer : Array < string | Uint8Array > ,
830
+ lastChunk : string | Uint8Array ,
831
+ ) : void {
832
+ let row = '' ;
833
+ const stringDecoder = response . _stringDecoder ;
834
+ for ( let i = 0 ; i < buffer . length ; i ++ ) {
835
+ const chunk = buffer [ i ] ;
836
+ if ( typeof chunk === 'string' ) {
837
+ row += chunk ;
838
+ } else {
839
+ row + = readPartialStringChunk ( stringDecoder , chunk ) ;
840
+ }
841
+ }
842
+ if ( typeof lastChunk === 'string' ) {
843
+ row += lastChunk ;
844
+ } else {
845
+ row += readFinalStringChunk ( stringDecoder , lastChunk ) ;
812
846
}
813
- const colon = row . indexOf ( ':' , 0 ) ;
814
- const id = parseInt ( row . slice ( 0 , colon ) , 16 ) ;
815
- const tag = row [ colon + 1 ] ;
816
- // When tags that are not text are added, check them here before
817
- // parsing the row as text.
818
- // switch (tag) {
819
- // }
820
847
switch ( tag ) {
821
- case 'I' : {
822
- resolveModule ( response , id , row . slice ( colon + 2 ) ) ;
848
+ case 73 /* "I" */ : {
849
+ resolveModule ( response , id , row ) ;
823
850
return ;
824
851
}
825
- case 'H' : {
826
- const code = row [ colon + 2 ] ;
827
- resolveHint ( response , code , row . slice ( colon + 3 ) ) ;
852
+ case 72 /* "H" */ : {
853
+ const code = row [ 0 ] ;
854
+ resolveHint ( response , code , row . slice ( 1 ) ) ;
828
855
return ;
829
856
}
830
- case 'E' : {
831
- const errorInfo = JSON . parse ( row . slice ( colon + 2 ) ) ;
857
+ case 69 /* "E" */ : {
858
+ const errorInfo = JSON . parse ( row ) ;
832
859
if ( __DEV__ ) {
833
860
resolveErrorDev (
834
861
response ,
@@ -844,7 +871,7 @@ function processFullRow(response: Response, row: string): void {
844
871
}
845
872
default : {
846
873
// We assume anything else is JSON.
847
- resolveModel ( response , id , row . slice ( colon + 1 ) ) ;
874
+ resolveModel ( response , id , row ) ;
848
875
return ;
849
876
}
850
877
}
@@ -854,18 +881,77 @@ export function processBinaryChunk(
854
881
response : Response ,
855
882
chunk : Uint8Array ,
856
883
) : void {
857
- const stringDecoder = response . _stringDecoder ;
858
- let linebreak = chunk . indexOf ( 10 ) ; // newline
859
- while ( linebreak > - 1 ) {
860
- const fullrow =
861
- response . _partialRow +
862
- readFinalStringChunk ( stringDecoder , chunk . subarray ( 0 , linebreak ) ) ;
863
- processFullRow ( response , fullrow ) ;
864
- response . _partialRow = '' ;
865
- chunk = chunk . subarray ( linebreak + 1 ) ;
866
- linebreak = chunk . indexOf ( 10 ) ; // newline
884
+ let i = 0 ;
885
+ while ( i < chunk . length ) {
886
+ let lastIdx = - 1 ;
887
+ switch ( response . _rowState ) {
888
+ case ROW_ID : {
889
+ const byte = chunk [ i ++ ] ;
890
+ if ( byte === 58 /* ":" */ ) {
891
+ // Finished the rowID, next we'll parse the tag.
892
+ response . _rowState = ROW_TAG ;
893
+ } else {
894
+ response . _rowID =
895
+ ( response . _rowID << 4 ) | ( byte > 96 ? byte - 87 : byte - 48 ) ;
896
+ }
897
+ continue ;
898
+ }
899
+ case ROW_TAG : {
900
+ const resolvedRowTag = chunk [ i ] ;
901
+ if ( resolvedRowTag > 64 && resolvedRowTag < 91 ) {
902
+ response . _rowTag = resolvedRowTag ;
903
+ i ++ ;
904
+ } else {
905
+ // This was an unknown tag so it was probably part of the data.
906
+ }
907
+ response . _rowState = ROW_CHUNK_BY_NEWLINE ;
908
+ continue ;
909
+ }
910
+ case ROW_LENGTH : {
911
+ // TODO
912
+ continue ;
913
+ }
914
+ case ROW_CHUNK_BY_NEWLINE : {
915
+ // We're looking for a newline
916
+ lastIdx = chunk . indexOf ( 10 /* "\n" */ , i ) ;
917
+ break ;
918
+ }
919
+ case ROW_CHUNK_BY_LENGTH : {
920
+ // We're looking for the remaining byte length
921
+ const rowLength = response . _rowLength ;
922
+ if ( i + rowLength <= chunk . length ) {
923
+ lastIdx = i + rowLength ;
924
+ }
925
+ break ;
926
+ }
927
+ }
928
+ if ( lastIdx > - 1 ) {
929
+ // We found the last chunk of the row
930
+ const lastChunk = chunk . slice ( i , lastIdx ) ;
931
+ processFullRow (
932
+ response ,
933
+ response . _rowID ,
934
+ response . _rowTag ,
935
+ response . _buffer ,
936
+ lastChunk ,
937
+ ) ;
938
+ // Reset state machine for a new row
939
+ response . _rowState = ROW_ID ;
940
+ response . _rowTag = 0 ;
941
+ response . _rowID = 0 ;
942
+ response . _rowLength = 0 ;
943
+ response . _buffer . length = 0 ;
944
+ i = lastIdx + 1 ;
945
+ } else {
946
+ // The rest of this row is in a future chunk. We stash the rest of the
947
+ // current chunk until we can process the full row.
948
+ const remainingSlice = chunk . slice ( i ) ;
949
+ response . _buffer . push ( remainingSlice ) ;
950
+ // Update how many bytes we're still waiting for.
951
+ response . _rowLength -= remainingSlice . length ;
952
+ break ;
953
+ }
867
954
}
868
- response . _partialRow += readPartialStringChunk ( stringDecoder , chunk ) ;
869
955
}
870
956
871
957
function parseModel < T > (response: Response, json: UninitializedModel): T {
0 commit comments