11import * as T from 'typings'
22import * as TT from 'typings/tutorial'
3+ import * as E from 'typings/error'
34import * as vscode from 'vscode'
45import saveCommit from '../actions/saveCommit'
56import setupActions from '../actions/setupActions'
@@ -10,6 +11,11 @@ import logger from '../services/logger'
1011import Context from './context'
1112import { version as gitVersion } from '../services/git'
1213import { openWorkspace , checkWorkspaceEmpty } from '../services/workspace'
14+ import { readFile } from 'fs'
15+ import { join } from 'path'
16+ import { promisify } from 'util'
17+
18+ const readFileAsync = promisify ( readFile )
1319
1420interface Channel {
1521 receive ( action : T . Action ) : Promise < void >
@@ -39,7 +45,9 @@ class Channel implements Channel {
3945 public receive = async ( action : T . Action ) => {
4046 // action may be an object.type or plain string
4147 const actionType : string = typeof action === 'string' ? action : action . type
42- const onError = ( error : T . ErrorMessage ) => this . send ( { type : 'ERROR' , payload : { error } } )
48+ // const onError = (error: T.ErrorMessage) => this.send({ type: 'ERROR', payload: { error } })
49+
50+ // console.log(`ACTION: ${actionType}`)
4351
4452 switch ( actionType ) {
4553 case 'EDITOR_ENV_GET' :
@@ -86,7 +94,16 @@ class Channel implements Channel {
8694 // setup tutorial config (save watcher, test runner, etc)
8795 await this . context . setTutorial ( this . workspaceState , data )
8896
89- await tutorialConfig ( { config : data . config } , onError )
97+ const error : E . ErrorMessage | void = await tutorialConfig ( { config : data . config } ) . catch ( ( error : Error ) => ( {
98+ type : 'UnknownError' ,
99+ message : `Location: tutorial config.\n\n${ error . message } ` ,
100+ } ) )
101+
102+ // has error
103+ if ( error && error . type ) {
104+ this . send ( { type : 'TUTORIAL_CONFIGURE_FAIL' , payload : { error } } )
105+ return
106+ }
90107
91108 // report back to the webview that setup is complete
92109 this . send ( { type : 'TUTORIAL_CONFIGURED' } )
@@ -97,34 +114,54 @@ class Channel implements Channel {
97114 throw new Error ( 'Invalid tutorial to continue' )
98115 }
99116 const continueConfig : TT . TutorialConfig = tutorialContinue . config
100- await tutorialConfig (
101- {
102- config : continueConfig ,
103- alreadyConfigured : true ,
104- } ,
105- onError ,
106- )
117+ await tutorialConfig ( {
118+ config : continueConfig ,
119+ alreadyConfigured : true ,
120+ } )
107121 // update the current stepId on startup
108122 vscode . commands . executeCommand ( COMMANDS . SET_CURRENT_STEP , action . payload )
109123 return
110124 case 'EDITOR_VALIDATE_SETUP' :
111125 // 1. check workspace is selected
112126 const isEmptyWorkspace = await checkWorkspaceEmpty ( this . workspaceRoot . uri . path )
113127 if ( ! isEmptyWorkspace ) {
114- this . send ( { type : 'NOT_EMPTY_WORKSPACE' } )
128+ const error : E . ErrorMessage = {
129+ type : 'WorkspaceNotEmpty' ,
130+ message : '' ,
131+ actions : [
132+ {
133+ label : 'Open Workspace' ,
134+ transition : 'REQUEST_WORKSPACE' ,
135+ } ,
136+ {
137+ label : 'Check Again' ,
138+ transition : 'RETRY' ,
139+ } ,
140+ ] ,
141+ }
142+ this . send ( { type : 'VALIDATE_SETUP_FAILED' , payload : { error } } )
115143 return
116144 }
117145 // 2. check Git is installed.
118146 // Should wait for workspace before running otherwise requires access to root folder
119147 const isGitInstalled = await gitVersion ( )
120148 if ( ! isGitInstalled ) {
121- this . send ( { type : 'GIT_NOT_INSTALLED' } )
149+ const error : E . ErrorMessage = {
150+ type : 'GitNotFound' ,
151+ message : '' ,
152+ actions : [
153+ {
154+ label : 'Check Again' ,
155+ transition : 'RETRY' ,
156+ } ,
157+ ] ,
158+ }
159+ this . send ( { type : 'VALIDATE_SETUP_FAILED' , payload : { error } } )
122160 return
123161 }
124162 this . send ( { type : 'SETUP_VALIDATED' } )
125163 return
126164 case 'EDITOR_REQUEST_WORKSPACE' :
127- console . log ( 'request workspace' )
128165 openWorkspace ( )
129166 return
130167 // load step actions (git commits, commands, open files)
@@ -146,6 +183,24 @@ class Channel implements Channel {
146183 }
147184 // send to webview
148185 public send = async ( action : T . Action ) => {
186+ // Error middleware
187+ if ( action ?. payload ?. error ?. type ) {
188+ // load error markdown message
189+ const error = action . payload . error
190+ const errorMarkdownFile = join ( __dirname , '..' , '..' , 'errors' , `${ action . payload . error . type } .md` )
191+ const errorMarkdown = await readFileAsync ( errorMarkdownFile ) . catch ( ( ) => {
192+ // onError(new Error(`Error Markdown file not found for ${action.type}`))
193+ } )
194+
195+ // log error to console for safe keeping
196+ console . log ( `ERROR:\n ${ errorMarkdown } ` )
197+
198+ if ( errorMarkdown ) {
199+ // add a clearer error message for the user
200+ error . message = `${ errorMarkdown } \n${ error . message } `
201+ }
202+ }
203+
149204 // action may be an object.type or plain string
150205 const actionType : string = typeof action === 'string' ? action : action . type
151206 switch ( actionType ) {
@@ -160,8 +215,9 @@ class Channel implements Channel {
160215 saveCommit ( )
161216 }
162217
163- const success = await this . postMessage ( action )
164- if ( ! success ) {
218+ // send message
219+ const sentToClient = await this . postMessage ( action )
220+ if ( ! sentToClient ) {
165221 throw new Error ( `Message post failure: ${ JSON . stringify ( action ) } ` )
166222 }
167223 }
0 commit comments