1+ // @ts -check 
2+ 
3+ export  class  CodeCompression  { 
4+     /** 
5+      * Compresses a string using gzip compression and returns base64-encoded result. 
6+      * @param  {string } text - The text to compress 
7+      * @returns  {Promise<string> } Base64-encoded compressed string 
8+      */ 
9+     static  async  compress ( text )  { 
10+         const  textEncoder  =  new  TextEncoder ( ) ; 
11+         const  stream  =  new  CompressionStream ( 'gzip' ) ; 
12+         const  writer  =  stream . writable . getWriter ( ) ; 
13+         const  reader  =  stream . readable . getReader ( ) ; 
14+ 
15+         // Start compression 
16+         const  writePromise  =  writer . write ( textEncoder . encode ( text ) ) . then ( ( )  =>  writer . close ( ) ) ; 
17+ 
18+         // Read compressed chunks 
19+         const  chunks  =  [ ] ; 
20+         let  readResult ; 
21+         do  { 
22+             readResult  =  await  reader . read ( ) ; 
23+             if  ( readResult . value )  { 
24+                 chunks . push ( readResult . value ) ; 
25+             } 
26+         }  while  ( ! readResult . done ) ; 
27+ 
28+         await  writePromise ; 
29+ 
30+         // Combine all chunks into single Uint8Array 
31+         const  totalLength  =  chunks . reduce ( ( sum ,  chunk )  =>  sum  +  chunk . length ,  0 ) ; 
32+         const  compressed  =  new  Uint8Array ( totalLength ) ; 
33+         let  offset  =  0 ; 
34+         for  ( const  chunk  of  chunks )  { 
35+             compressed . set ( chunk ,  offset ) ; 
36+             offset  +=  chunk . length ; 
37+         } 
38+ 
39+         // Convert to base64 for URL safety 
40+         return  this . uint8ArrayToBase64 ( compressed ) ; 
41+     } 
42+ 
43+     /** 
44+      * Decompresses a base64-encoded gzip string back to original text. 
45+      * @param  {string } compressedBase64 - Base64-encoded compressed string 
46+      * @returns  {Promise<string> } Original decompressed text 
47+      */ 
48+     static  async  decompress ( compressedBase64 )  { 
49+         const  compressed  =  this . base64ToUint8Array ( compressedBase64 ) ; 
50+         const  stream  =  new  DecompressionStream ( 'gzip' ) ; 
51+         const  writer  =  stream . writable . getWriter ( ) ; 
52+         const  reader  =  stream . readable . getReader ( ) ; 
53+ 
54+         // Start decompression 
55+         const  writePromise  =  writer . write ( compressed ) . then ( ( )  =>  writer . close ( ) ) ; 
56+ 
57+         // Read decompressed chunks 
58+         const  chunks  =  [ ] ; 
59+         let  readResult ; 
60+         do  { 
61+             readResult  =  await  reader . read ( ) ; 
62+             if  ( readResult . value )  { 
63+                 chunks . push ( readResult . value ) ; 
64+             } 
65+         }  while  ( ! readResult . done ) ; 
66+ 
67+         await  writePromise ; 
68+ 
69+         // Combine chunks and decode 
70+         const  totalLength  =  chunks . reduce ( ( sum ,  chunk )  =>  sum  +  chunk . length ,  0 ) ; 
71+         const  decompressed  =  new  Uint8Array ( totalLength ) ; 
72+         let  offset  =  0 ; 
73+         for  ( const  chunk  of  chunks )  { 
74+             decompressed . set ( chunk ,  offset ) ; 
75+             offset  +=  chunk . length ; 
76+         } 
77+ 
78+         const  textDecoder  =  new  TextDecoder ( ) ; 
79+         return  textDecoder . decode ( decompressed ) ; 
80+     } 
81+ 
82+     /** 
83+      * Converts Uint8Array to base64 string. 
84+      * @param  {Uint8Array } uint8Array - Array to convert 
85+      * @returns  {string } Base64 string 
86+      */ 
87+     static  uint8ArrayToBase64 ( uint8Array )  { 
88+         let  binary  =  '' ; 
89+         for  ( let  i  =  0 ;  i  <  uint8Array . byteLength ;  i ++ )  { 
90+             binary  +=  String . fromCharCode ( uint8Array [ i ] ) ; 
91+         } 
92+         return  btoa ( binary ) ; 
93+     } 
94+ 
95+     /** 
96+      * Converts base64 string to Uint8Array. 
97+      * @param  {string } base64 - Base64 string to convert 
98+      * @returns  {Uint8Array } Converted array 
99+      */ 
100+     static  base64ToUint8Array ( base64 )  { 
101+         const  binary  =  atob ( base64 ) ; 
102+         const  bytes  =  new  Uint8Array ( binary . length ) ; 
103+         for  ( let  i  =  0 ;  i  <  binary . length ;  i ++ )  { 
104+             bytes [ i ]  =  binary . charCodeAt ( i ) ; 
105+         } 
106+         return  bytes ; 
107+     } 
108+ } 
109+ 
110+ /** 
111+  * URL parameter manager for sharing code. 
112+  * Handles compression, URL generation, and parameter extraction with encoding type versioning. 
113+  */ 
114+ export  class  CodeShareManager  { 
115+     /** @type  {string } */ 
116+     static  CURRENT_ENCODING  =  'gzip-b64' ; 
117+ 
118+     /** 
119+      * Available encoding types for future extensibility. 
120+      * @type  {Object<string, {compress: function, decompress: function}> } 
121+      */ 
122+     static  ENCODERS  =  { 
123+         'gzip-b64' : { 
124+             compress : CodeCompression . compress . bind ( CodeCompression ) , 
125+             decompress : CodeCompression . decompress . bind ( CodeCompression ) 
126+         } 
127+     } ; 
128+ 
129+     /** 
130+      * Generates a shareable URL with compressed code and encoding type. 
131+      * @param  {Object } code - Code object containing swift and dts properties 
132+      * @param  {string } code.swift - Swift code 
133+      * @param  {string } code.dts - TypeScript definition code 
134+      * @returns  {Promise<string> } Shareable URL 
135+      */ 
136+     static  async  generateShareUrl ( code )  { 
137+         const  codeData  =  JSON . stringify ( code ) ; 
138+         const  encoder  =  this . ENCODERS [ this . CURRENT_ENCODING ] ; 
139+ 
140+         if  ( ! encoder )  { 
141+             throw  new  Error ( `Unsupported encoding type: ${ this . CURRENT_ENCODING }  ` ) ; 
142+         } 
143+ 
144+         const  compressed  =  await  encoder . compress ( codeData ) ; 
145+ 
146+         const  url  =  new  URL ( window . location . href ) ; 
147+         url . searchParams . set ( 'code' ,  compressed ) ; 
148+         url . searchParams . set ( 'enc' ,  this . CURRENT_ENCODING ) ; 
149+ 
150+         return  url . toString ( ) ; 
151+     } 
152+ 
153+     /** 
154+      * Extracts code from URL parameters with encoding type detection. 
155+      * @param  {string } [url] - URL to extract from (defaults to current URL) 
156+      * @returns  {Promise<Object|null> } Code object or null if no code found 
157+      */ 
158+     static  async  extractCodeFromUrl ( url )  { 
159+         const  urlObj  =  new  URL ( url  ||  window . location . href ) ; 
160+         const  compressedCode  =  urlObj . searchParams . get ( 'code' ) ; 
161+         const  encodingType  =  urlObj . searchParams . get ( 'enc' )  ||  this . CURRENT_ENCODING ; 
162+ 
163+         if  ( ! compressedCode )  { 
164+             return  null ; 
165+         } 
166+ 
167+         const  encoder  =  this . ENCODERS [ encodingType ] ; 
168+         if  ( ! encoder )  { 
169+             console . error ( `Unsupported encoding type: ${ encodingType }  ` ) ; 
170+             throw  new  Error ( `Unsupported encoding type: ${ encodingType }  . Supported types: ${ Object . keys ( this . ENCODERS ) . join ( ', ' ) }  ` ) ; 
171+         } 
172+ 
173+         try  { 
174+             const  decompressed  =  await  encoder . decompress ( compressedCode ) ; 
175+             return  JSON . parse ( decompressed ) ; 
176+         }  catch  ( error )  { 
177+             console . error ( 'Failed to extract code from URL:' ,  error ) ; 
178+             throw  new  Error ( `Failed to decode shared code (encoding: ${ encodingType }  ): ${ error . message }  ` ) ; 
179+         } 
180+     } 
181+ 
182+     /** 
183+      * Checks if current URL contains shared code. 
184+      * @returns  {boolean } True if URL contains code parameter 
185+      */ 
186+     static  hasSharedCode ( )  { 
187+         return  new  URL ( window . location . href ) . searchParams . has ( 'code' ) ; 
188+     } 
189+ } 
0 commit comments