@@ -39,6 +39,7 @@ export class XDebugError extends Error {
3939 constructor ( message : string , code : number ) {
4040 super ( message ) ;
4141 this . code = code ;
42+ this . name = 'XDebugError' ;
4243 }
4344}
4445
@@ -108,42 +109,124 @@ export class StatusResponse extends Response {
108109 }
109110}
110111
111- /** Returned by a breakpoint_list command */
112- export class Breakpoint {
113- /** Unique ID which is used for modifying the breakpoint */
112+ /** Abstract base class for all breakpoints */
113+ export abstract class Breakpoint {
114+ /** Unique ID which is used for modifying the breakpoint (only when received through breakpoint_list) */
114115 id : number ;
115116 /** The type of the breakpoint: line, call, return, exception, conditional or watch */
116117 type : string ;
117118 /** State of the breakpoint: enabled, disabled */
118119 state : string ;
119- /** File URI, if type is line */
120- fileUri : string ;
121- /** Line, if type is line */
122- line : number ;
123- /** Exception, if type is exception */
124- exception : string ;
125120 /** The connection this breakpoint is set on */
126121 connection : Connection ;
127- /**
128- * @param {Element } breakpointNode
129- * @param {Connection } connection
130- */
131- constructor ( breakpointNode : Element , connection : Connection ) {
132- this . id = parseInt ( breakpointNode . getAttribute ( 'id' ) ) ;
133- this . type = breakpointNode . getAttribute ( 'type' ) ;
134- if ( this . type === 'line' ) {
135- this . line = parseInt ( breakpointNode . getAttribute ( 'line' ) ) ;
136- } else if ( this . type === 'exception' ) {
137- this . exception = breakpointNode . getAttribute ( 'exception' ) ;
122+ /** dynamically detects the type of breakpoint and returns the appropiate object */
123+ public static fromXml ( breakpointNode : Element , connection : Connection ) : Breakpoint {
124+ switch ( breakpointNode . getAttribute ( 'type' ) ) {
125+ case 'exception' : return new ExceptionBreakpoint ( breakpointNode , connection ) ;
126+ case 'line' : return new LineBreakpoint ( breakpointNode , connection ) ;
127+ case 'conditional' : return new ConditionalBreakpoint ( breakpointNode , connection ) ;
128+ }
129+ }
130+ /** Constructs a breakpoint object from an XML node from a XDebug response */
131+ constructor ( breakpointNode : Element , connection : Connection ) ;
132+ /** To create a new breakpoint in derived classes */
133+ constructor ( type : string ) ;
134+ constructor ( ) {
135+ if ( typeof arguments [ 0 ] === 'object' ) {
136+ // from XML
137+ const breakpointNode : Element = arguments [ 0 ] ;
138+ this . connection = arguments [ 1 ] ;
139+ this . type = breakpointNode . getAttribute ( 'type' ) ;
140+ this . id = parseInt ( breakpointNode . getAttribute ( 'id' ) ) ;
141+ this . state = breakpointNode . getAttribute ( 'state' ) ;
142+ } else {
143+ this . type = arguments [ 0 ] ;
138144 }
139- this . connection = connection ;
140145 }
141146 /** Removes the breakpoint by sending a breakpoint_remove command */
142147 public remove ( ) {
143148 return this . connection . sendBreakpointRemoveCommand ( this ) ;
144149 }
145150}
146151
152+ /** class for line breakpoints. Returned from a breakpoint_list or passed to sendBreakpointSetCommand */
153+ export class LineBreakpoint extends Breakpoint {
154+ /** File URI of the file in which to break */
155+ fileUri : string ;
156+ /** Line to break on */
157+ line : number ;
158+ /** constructs a line breakpoint from an XML node */
159+ constructor ( breakpointNode : Element , connection : Connection ) ;
160+ /** contructs a line breakpoint for passing to sendSetBreakpointCommand */
161+ constructor ( fileUri : string , line : number ) ;
162+ constructor ( ) {
163+ if ( typeof arguments [ 0 ] === 'object' ) {
164+ const breakpointNode : Element = arguments [ 0 ] ;
165+ const connection : Connection = arguments [ 1 ] ;
166+ super ( breakpointNode , connection ) ;
167+ this . line = parseInt ( breakpointNode . getAttribute ( 'line' ) ) ;
168+ } else {
169+ // construct from arguments
170+ this . fileUri = arguments [ 0 ] ;
171+ this . line = arguments [ 1 ] ;
172+ super ( 'line' ) ;
173+ }
174+ }
175+ }
176+
177+ /** class for exception breakpoints. Returned from a breakpoint_list or passed to sendBreakpointSetCommand */
178+ export class ExceptionBreakpoint extends Breakpoint {
179+ /** The Exception name to break on. Can also contain wildcards. */
180+ exception : string ;
181+ /** Constructs a breakpoint object from an XML node from a XDebug response */
182+ constructor ( breakpointNode : Element , connection : Connection ) ;
183+ /** Constructs a breakpoint for passing it to sendSetBreakpointCommand */
184+ constructor ( exception : string ) ;
185+ constructor ( ) {
186+ if ( typeof arguments [ 0 ] === 'object' ) {
187+ // from XML
188+ const breakpointNode : Element = arguments [ 0 ] ;
189+ const connection : Connection = arguments [ 1 ] ;
190+ super ( breakpointNode , connection ) ;
191+ this . exception = breakpointNode . getAttribute ( 'exception' ) ;
192+ } else {
193+ // from arguments
194+ super ( 'exception' ) ;
195+ this . exception = arguments [ 0 ] ;
196+ }
197+ }
198+ }
199+
200+ /** class for conditional breakpoints. Returned from a breakpoint_list or passed to sendBreakpointSetCommand */
201+ export class ConditionalBreakpoint extends Breakpoint {
202+ /** File URI */
203+ fileUri : string ;
204+ /** Line (optional)*/
205+ line : number ;
206+ /** The PHP expression under which to break on */
207+ expression : string ;
208+ /** Constructs a breakpoint object from an XML node from a XDebug response */
209+ constructor ( breakpointNode : Element , connection : Connection ) ;
210+ /** Contructs a breakpoint object for passing to sendSetBreakpointCommand */
211+ constructor ( expression : string , fileUri : string , line ?: number ) ;
212+ constructor ( ) {
213+ if ( typeof arguments [ 0 ] === 'object' ) {
214+ // from XML
215+ const breakpointNode : Element = arguments [ 0 ] ;
216+ const connection : Connection = arguments [ 1 ] ;
217+ super ( breakpointNode , connection ) ;
218+ this . expression = breakpointNode . getAttribute ( 'expression' ) ; // Base64 encoded?
219+ } else {
220+ // from arguments
221+ super ( 'conditional' ) ;
222+ this . expression = arguments [ 0 ] ;
223+ this . fileUri = arguments [ 1 ] ;
224+ this . line = arguments [ 2 ] ;
225+ }
226+ }
227+ }
228+
229+ /** Response to a breakpoint_set command */
147230export class BreakpointSetResponse extends Response {
148231 breakpointId : number ;
149232 constructor ( document : XMLDocument , connection : Connection ) {
@@ -162,7 +245,7 @@ export class BreakpointListResponse extends Response {
162245 */
163246 constructor ( document : XMLDocument , connection : Connection ) {
164247 super ( document , connection ) ;
165- this . breakpoints = Array . from ( document . documentElement . childNodes ) . map ( ( breakpointNode : Element ) => new Breakpoint ( breakpointNode , connection ) ) ;
248+ this . breakpoints = Array . from ( document . documentElement . childNodes ) . map ( ( breakpointNode : Element ) => Breakpoint . fromXml ( breakpointNode , connection ) ) ;
166249 }
167250}
168251
@@ -563,23 +646,24 @@ export class Connection extends DbgpConnection {
563646
564647 /**
565648 * Sends a breakpoint_set command that sets a breakpoint.
566- * @param {object } breakpoint
567- * @param {string } breakpoint.type - the type of breakpoint. Can be 'line' or 'exception'
568- * @param {string } [breakpoint.fileUri] - the file URI to break on if type is 'line'
569- * @param {number } [breakpoint.line] - the line to break on if type is 'line'
570- * @param {string } [breakpoint.exception] - the exception class name to break on if type is 'exception'
649+ * @param {Breakpoint } breakpoint - an instance of LineBreakpoint, ConditionalBreakpoint or ExceptionBreakpoint
571650 * @returns Promise.<BreakpointSetResponse>
572651 */
573- public sendBreakpointSetCommand ( breakpoint : { type : string , fileUri ?: string , line ?: number , exception ?: string } ) : Promise < BreakpointSetResponse > {
574- let args = `-t ${ breakpoint . type } ` ;
575- if ( breakpoint . type === 'line' ) {
576- args += `-f ${ breakpoint . fileUri } -n ${ breakpoint . line } ` ;
577- } else if ( breakpoint . type === 'exception' ) {
578- args += `-x ${ breakpoint . exception } ` ;
579- } else {
580- return Promise . reject < BreakpointSetResponse > ( new Error ( 'unsupported breakpoint type' ) ) ;
652+ public sendBreakpointSetCommand ( breakpoint : Breakpoint ) : Promise < BreakpointSetResponse > {
653+ let args = `-t ${ breakpoint . type } ` ;
654+ let data : string ;
655+ if ( breakpoint instanceof LineBreakpoint ) {
656+ args += ` -f ${ breakpoint . fileUri } -n ${ breakpoint . line } ` ;
657+ } else if ( breakpoint instanceof ExceptionBreakpoint ) {
658+ args += ` -x ${ breakpoint . exception } ` ;
659+ } else if ( breakpoint instanceof ConditionalBreakpoint ) {
660+ args += ` -f ${ breakpoint . fileUri } ` ;
661+ if ( typeof breakpoint . line === 'number' ) {
662+ args += ` -n ${ breakpoint . line } ` ;
663+ }
664+ data = breakpoint . expression ;
581665 }
582- return this . _enqueueCommand ( 'breakpoint_set' , args ) . then ( document => new BreakpointSetResponse ( document , this ) ) ;
666+ return this . _enqueueCommand ( 'breakpoint_set' , args , data ) . then ( document => new BreakpointSetResponse ( document , this ) ) ;
583667 }
584668
585669 /** sends a breakpoint_list command */
0 commit comments