|
1 | 1 | import { ref, reactive } from 'vue' |
2 | | -import type { WebRMessage, CsvData } from '@/types' |
| 2 | +import type { WebRMessage, CsvData, WebROutputItem, WebRCharacterObject, WebRListObject, WebRProxy, WebRExecutionResult } from '@/types' |
| 3 | + |
| 4 | +// WebR output type mapping - immutable and reusable |
| 5 | +const WEBR_TYPE_MAP = { |
| 6 | + stdout: 'stdout', |
| 7 | + stderr: 'stderr', |
| 8 | + message: 'info', |
| 9 | + warning: 'warning', |
| 10 | + error: 'error' |
| 11 | +} as const satisfies Record<string, WebRMessage['type']> |
| 12 | + |
| 13 | +// Type guards for WebR objects |
| 14 | +const isWebRCharacterObject = (obj: unknown): obj is WebRCharacterObject => { |
| 15 | + return typeof obj === 'object' && obj !== null && |
| 16 | + 'type' in obj && obj.type === 'character' && |
| 17 | + 'values' in obj && Array.isArray(obj.values) |
| 18 | +} |
| 19 | + |
| 20 | +const isWebRListObject = (obj: unknown): obj is WebRListObject => { |
| 21 | + return typeof obj === 'object' && obj !== null && |
| 22 | + 'type' in obj && obj.type === 'list' && |
| 23 | + 'values' in obj && Array.isArray(obj.values) |
| 24 | +} |
| 25 | + |
| 26 | +// Extract content from WebR output with proper type checking |
| 27 | +const extractContentFromWebROutput = async (output: WebROutputItem): Promise<string> => { |
| 28 | + if (typeof output.data === 'string') { |
| 29 | + return output.data |
| 30 | + } |
| 31 | + |
| 32 | + // Convert WebR proxy to JavaScript object |
| 33 | + const proxy = output.data as WebRProxy |
| 34 | + const jsResult = await proxy.toJs() |
| 35 | + |
| 36 | + if (isWebRCharacterObject(jsResult)) { |
| 37 | + return jsResult.values.join('\n') |
| 38 | + } |
| 39 | + |
| 40 | + if (isWebRListObject(jsResult)) { |
| 41 | + // Validate assumption: we expect only 1 message in the list |
| 42 | + if (jsResult.values.length > 1) { |
| 43 | + console.error(`ASSUMPTION VIOLATION: List has ${jsResult.values.length} values, expected 1:`, jsResult) |
| 44 | + } |
| 45 | + |
| 46 | + const messageObject = jsResult.values[0] |
| 47 | + if (isWebRCharacterObject(messageObject) && messageObject.values.length > 0) { |
| 48 | + return messageObject.values.join('\n') |
| 49 | + } |
| 50 | + |
| 51 | + console.error('Unexpected list structure:', jsResult) |
| 52 | + return '[Unable to extract message from list]' |
| 53 | + } |
| 54 | + |
| 55 | + console.error('Unknown WebR object type:', jsResult) |
| 56 | + return `[Unknown WebR type: ${(jsResult as any)?.type || 'unknown'}]` |
| 57 | +} |
3 | 58 |
|
4 | 59 | export const useWebR = () => { |
5 | 60 | const isReady = ref(false) |
@@ -88,19 +143,25 @@ export const useWebR = () => { |
88 | 143 | const result = await shelter.captureR(code, { |
89 | 144 | withAutoprint: true, |
90 | 145 | captureStreams: true, |
91 | | - captureConditions: false, |
| 146 | + captureConditions: true, |
92 | 147 | captureGraphics: true, |
93 | 148 | env: webR.objs.globalEnv, |
94 | 149 | }) |
95 | 150 |
|
96 | | - // Process stdout |
97 | | - if (result.output && result.output.length > 0) { |
98 | | - for (const output of result.output) { |
99 | | - if (output.type === 'stdout' && output.data) { |
100 | | - addMessage('stdout', output.data) |
101 | | - } else if (output.type === 'stderr' && output.data) { |
102 | | - addMessage('stderr', output.data) |
| 151 | + // Process all output (streams and conditions) |
| 152 | + const typedResult = result as WebRExecutionResult |
| 153 | + if (typedResult.output && typedResult.output.length > 0) { |
| 154 | + for (const output of typedResult.output) { |
| 155 | + const content = await extractContentFromWebROutput(output) |
| 156 | + const messageType = WEBR_TYPE_MAP[output.type as keyof typeof WEBR_TYPE_MAP] |
| 157 | + |
| 158 | + if (!messageType) { |
| 159 | + console.error(`Unknown WebR output type: ${output.type}`) |
| 160 | + addMessage('error', `Unknown output type: ${output.type}`) |
| 161 | + continue |
103 | 162 | } |
| 163 | + |
| 164 | + addMessage(messageType, content) |
104 | 165 | } |
105 | 166 | } |
106 | 167 |
|
|
0 commit comments