1+ import { NotebookCellOutputItem } from 'vscode' ;
2+ import { parseJsonSafely , convertBase64ToUint8Array } from './dataConversionUtils' ;
3+
4+ export interface MimeProcessor {
5+ canHandle ( mimeType : string ) : boolean ;
6+ processForDeepnote ( content : unknown , mimeType : string ) : unknown ;
7+ processForVSCode ( content : unknown , mimeType : string ) : NotebookCellOutputItem | null ;
8+ }
9+
10+ /**
11+ * Handles text-based MIME types
12+ */
13+ export class TextMimeProcessor implements MimeProcessor {
14+ private readonly supportedTypes = [ 'text/plain' , 'text/html' ] ;
15+
16+ canHandle ( mimeType : string ) : boolean {
17+ return this . supportedTypes . includes ( mimeType ) ;
18+ }
19+
20+ processForDeepnote ( content : unknown ) : unknown {
21+ return typeof content === 'string' ? content : String ( content ) ;
22+ }
23+
24+ processForVSCode ( content : unknown , mimeType : string ) : NotebookCellOutputItem | null {
25+ if ( mimeType === 'text/plain' ) {
26+ return NotebookCellOutputItem . text ( content as string ) ;
27+ }
28+ if ( mimeType === 'text/html' ) {
29+ return NotebookCellOutputItem . text ( content as string , 'text/html' ) ;
30+ }
31+ return null ;
32+ }
33+ }
34+
35+ /**
36+ * Handles image MIME types
37+ */
38+ export class ImageMimeProcessor implements MimeProcessor {
39+ canHandle ( mimeType : string ) : boolean {
40+ return mimeType . startsWith ( 'image/' ) ;
41+ }
42+
43+ processForDeepnote ( content : unknown , mimeType : string ) : unknown {
44+ if ( content instanceof Uint8Array ) {
45+ const base64String = btoa ( String . fromCharCode ( ...content ) ) ;
46+ return `data:${ mimeType } ;base64,${ base64String } ` ;
47+ }
48+ return content ;
49+ }
50+
51+ processForVSCode ( content : unknown , mimeType : string ) : NotebookCellOutputItem | null {
52+ try {
53+ let uint8Array : Uint8Array ;
54+
55+ if ( typeof content === 'string' ) {
56+ uint8Array = convertBase64ToUint8Array ( content ) ;
57+ } else if ( content instanceof ArrayBuffer ) {
58+ uint8Array = new Uint8Array ( content ) ;
59+ } else if ( content instanceof Uint8Array ) {
60+ uint8Array = content ;
61+ } else {
62+ return null ;
63+ }
64+
65+ return NotebookCellOutputItem . binary ( uint8Array , mimeType ) ;
66+ } catch {
67+ return NotebookCellOutputItem . text ( String ( content ) , mimeType ) ;
68+ }
69+ }
70+ }
71+
72+ /**
73+ * Handles JSON MIME types
74+ */
75+ export class JsonMimeProcessor implements MimeProcessor {
76+ canHandle ( mimeType : string ) : boolean {
77+ return mimeType === 'application/json' ;
78+ }
79+
80+ processForDeepnote ( content : unknown ) : unknown {
81+ if ( typeof content === 'string' ) {
82+ return parseJsonSafely ( content ) ;
83+ }
84+ return content ;
85+ }
86+
87+ processForVSCode ( content : unknown , mimeType : string ) : NotebookCellOutputItem | null {
88+ try {
89+ let jsonObject : unknown ;
90+
91+ if ( typeof content === 'string' ) {
92+ jsonObject = JSON . parse ( content ) ;
93+ } else if ( typeof content === 'object' && content !== null ) {
94+ jsonObject = content ;
95+ } else {
96+ return NotebookCellOutputItem . text ( String ( content ) , mimeType ) ;
97+ }
98+
99+ return NotebookCellOutputItem . text ( JSON . stringify ( jsonObject , null , 2 ) , mimeType ) ;
100+ } catch {
101+ return NotebookCellOutputItem . text ( String ( content ) , mimeType ) ;
102+ }
103+ }
104+ }
105+
106+ /**
107+ * Handles other application MIME types
108+ */
109+ export class ApplicationMimeProcessor implements MimeProcessor {
110+ canHandle ( mimeType : string ) : boolean {
111+ return mimeType . startsWith ( 'application/' ) && mimeType !== 'application/json' ;
112+ }
113+
114+ processForDeepnote ( content : unknown ) : unknown {
115+ if ( typeof content === 'string' ) {
116+ return parseJsonSafely ( content ) ;
117+ }
118+ return content ;
119+ }
120+
121+ processForVSCode ( content : unknown , mimeType : string ) : NotebookCellOutputItem | null {
122+ const textContent = typeof content === 'string' ? content : JSON . stringify ( content , null , 2 ) ;
123+ return NotebookCellOutputItem . text ( textContent , mimeType ) ;
124+ }
125+ }
126+
127+ /**
128+ * Generic fallback processor
129+ */
130+ export class GenericMimeProcessor implements MimeProcessor {
131+ canHandle ( ) : boolean {
132+ return true ; // Always can handle as fallback
133+ }
134+
135+ processForDeepnote ( content : unknown ) : unknown {
136+ return content ;
137+ }
138+
139+ processForVSCode ( content : unknown , mimeType : string ) : NotebookCellOutputItem | null {
140+ return NotebookCellOutputItem . text ( String ( content ) , mimeType ) ;
141+ }
142+ }
143+
144+ /**
145+ * Registry for MIME type processors
146+ */
147+ export class MimeTypeProcessorRegistry {
148+ private readonly processors : MimeProcessor [ ] = [
149+ new TextMimeProcessor ( ) ,
150+ new ImageMimeProcessor ( ) ,
151+ new JsonMimeProcessor ( ) ,
152+ new ApplicationMimeProcessor ( ) ,
153+ new GenericMimeProcessor ( ) // Must be last as fallback
154+ ] ;
155+
156+ getProcessor ( mimeType : string ) : MimeProcessor {
157+ return this . processors . find ( processor => processor . canHandle ( mimeType ) ) || new GenericMimeProcessor ( ) ;
158+ }
159+
160+ processForDeepnote ( content : unknown , mimeType : string ) : unknown {
161+ const processor = this . getProcessor ( mimeType ) ;
162+ return processor . processForDeepnote ( content , mimeType ) ;
163+ }
164+
165+ processForVSCode ( content : unknown , mimeType : string ) : NotebookCellOutputItem | null {
166+ const processor = this . getProcessor ( mimeType ) ;
167+ return processor . processForVSCode ( content , mimeType ) ;
168+ }
169+ }
0 commit comments