@@ -521,6 +521,18 @@ namespace ts {
521521 return result || array ;
522522 }
523523
524+ export function mapDefined < T > ( array : ReadonlyArray < T > , mapFn : ( x : T , i : number ) => T | undefined ) : ReadonlyArray < T > {
525+ const result : T [ ] = [ ] ;
526+ for ( let i = 0 ; i < array . length ; i ++ ) {
527+ const item = array [ i ] ;
528+ const mapped = mapFn ( item , i ) ;
529+ if ( mapped !== undefined ) {
530+ result . push ( mapped ) ;
531+ }
532+ }
533+ return result ;
534+ }
535+
524536 /**
525537 * Computes the first matching span of elements and returns a tuple of the first span
526538 * and the remaining elements.
@@ -740,18 +752,34 @@ namespace ts {
740752 return to ;
741753 }
742754
755+ /**
756+ * Gets the actual offset into an array for a relative offset. Negative offsets indicate a
757+ * position offset from the end of the array.
758+ */
759+ function toOffset ( array : any [ ] , offset : number ) {
760+ return offset < 0 ? array . length + offset : offset ;
761+ }
762+
743763 /**
744764 * Appends a range of value to an array, returning the array.
745765 *
746766 * @param to The array to which `value` is to be appended. If `to` is `undefined`, a new array
747767 * is created if `value` was appended.
748768 * @param from The values to append to the array. If `from` is `undefined`, nothing is
749769 * appended. If an element of `from` is `undefined`, that element is not appended.
770+ * @param start The offset in `from` at which to start copying values.
771+ * @param end The offset in `from` at which to stop copying values (non-inclusive).
750772 */
751- export function addRange < T > ( to : T [ ] | undefined , from : T [ ] | undefined ) : T [ ] | undefined {
773+ export function addRange < T > ( to : T [ ] | undefined , from : T [ ] | undefined , start ?: number , end ?: number ) : T [ ] | undefined {
752774 if ( from === undefined ) return to ;
753- for ( const v of from ) {
754- to = append ( to , v ) ;
775+ if ( to === undefined ) return from . slice ( start , end ) ;
776+ start = start === undefined ? 0 : toOffset ( from , start ) ;
777+ end = end === undefined ? from . length : toOffset ( from , end ) ;
778+ for ( let i = start ; i < end && i < from . length ; i ++ ) {
779+ const v = from [ i ] ;
780+ if ( v !== undefined ) {
781+ to . push ( from [ i ] ) ;
782+ }
755783 }
756784 return to ;
757785 }
@@ -776,28 +804,38 @@ namespace ts {
776804 return true ;
777805 }
778806
807+ /**
808+ * Returns the element at a specific offset in an array if non-empty, `undefined` otherwise.
809+ * A negative offset indicates the element should be retrieved from the end of the array.
810+ */
811+ export function elementAt < T > ( array : T [ ] | undefined , offset : number ) : T | undefined {
812+ if ( array ) {
813+ offset = toOffset ( array , offset ) ;
814+ if ( offset < array . length ) {
815+ return array [ offset ] ;
816+ }
817+ }
818+ return undefined ;
819+ }
820+
779821 /**
780822 * Returns the first element of an array if non-empty, `undefined` otherwise.
781823 */
782- export function firstOrUndefined < T > ( array : T [ ] ) : T {
783- return array && array . length > 0
784- ? array [ 0 ]
785- : undefined ;
824+ export function firstOrUndefined < T > ( array : T [ ] ) : T | undefined {
825+ return elementAt ( array , 0 ) ;
786826 }
787827
788828 /**
789829 * Returns the last element of an array if non-empty, `undefined` otherwise.
790830 */
791- export function lastOrUndefined < T > ( array : T [ ] ) : T {
792- return array && array . length > 0
793- ? array [ array . length - 1 ]
794- : undefined ;
831+ export function lastOrUndefined < T > ( array : T [ ] ) : T | undefined {
832+ return elementAt ( array , - 1 ) ;
795833 }
796834
797835 /**
798836 * Returns the only element of an array if it contains only one element, `undefined` otherwise.
799837 */
800- export function singleOrUndefined < T > ( array : T [ ] ) : T {
838+ export function singleOrUndefined < T > ( array : T [ ] ) : T | undefined {
801839 return array && array . length === 1
802840 ? array [ 0 ]
803841 : undefined ;
@@ -1125,6 +1163,15 @@ namespace ts {
11251163 return Array . isArray ? Array . isArray ( value ) : value instanceof Array ;
11261164 }
11271165
1166+ export function tryCast < TOut extends TIn , TIn = any > ( value : TIn | undefined , test : ( value : TIn ) => value is TOut ) : TOut | undefined {
1167+ return value !== undefined && test ( value ) ? value : undefined ;
1168+ }
1169+
1170+ export function cast < TOut extends TIn , TIn = any > ( value : TIn | undefined , test : ( value : TIn ) => value is TOut ) : TOut {
1171+ if ( value !== undefined && test ( value ) ) return value ;
1172+ Debug . fail ( `Invalid cast. The supplied value did not pass the test '${ Debug . getFunctionName ( test ) } '.` ) ;
1173+ }
1174+
11281175 /** Does nothing. */
11291176 export function noop ( ) : void { }
11301177
@@ -2210,8 +2257,11 @@ namespace ts {
22102257 this . declarations = undefined ;
22112258 }
22122259
2213- function Type ( this : Type , _checker : TypeChecker , flags : TypeFlags ) {
2260+ function Type ( this : Type , checker : TypeChecker , flags : TypeFlags ) {
22142261 this . flags = flags ;
2262+ if ( Debug . isDebugging ) {
2263+ this . checker = checker ;
2264+ }
22152265 }
22162266
22172267 function Signature ( ) {
@@ -2248,24 +2298,42 @@ namespace ts {
22482298
22492299 export namespace Debug {
22502300 export let currentAssertionLevel = AssertionLevel . None ;
2301+ export let isDebugging = false ;
22512302
22522303 export function shouldAssert ( level : AssertionLevel ) : boolean {
22532304 return currentAssertionLevel >= level ;
22542305 }
22552306
2256- export function assert ( expression : boolean , message ?: string , verboseDebugInfo ?: ( ) => string ) : void {
2307+ export function assert ( expression : boolean , message ?: string , verboseDebugInfo ?: ( ) => string , stackCrawlMark ?: Function ) : void {
22572308 if ( ! expression ) {
2258- let verboseDebugString = "" ;
22592309 if ( verboseDebugInfo ) {
2260- verboseDebugString = "\r\nVerbose Debug Information: " + verboseDebugInfo ( ) ;
2310+ message + = "\r\nVerbose Debug Information: " + verboseDebugInfo ( ) ;
22612311 }
2262- debugger ;
2263- throw new Error ( "Debug Failure. False expression: " + ( message || "" ) + verboseDebugString ) ;
2312+ fail ( message ? "False expression: " + message : "False expression." , stackCrawlMark || assert ) ;
22642313 }
22652314 }
22662315
2267- export function fail ( message ?: string ) : void {
2268- Debug . assert ( /*expression*/ false , message ) ;
2316+ export function fail ( message ?: string , stackCrawlMark ?: Function ) : void {
2317+ debugger ;
2318+ const e = new Error ( message ? `Debug Failure. ` : "Debug Failure." ) ;
2319+ if ( ( < any > Error ) . captureStackTrace ) {
2320+ ( < any > Error ) . captureStackTrace ( e , stackCrawlMark || fail ) ;
2321+ }
2322+ throw e ;
2323+ }
2324+
2325+ export function getFunctionName ( func : Function ) {
2326+ if ( typeof func !== "function" ) {
2327+ return "" ;
2328+ }
2329+ else if ( func . hasOwnProperty ( "name" ) ) {
2330+ return ( < any > func ) . name ;
2331+ }
2332+ else {
2333+ const text = Function . prototype . toString . call ( func ) ;
2334+ const match = / ^ f u n c t i o n \s + ( [ \w \$ ] + ) \s * \( / . exec ( text ) ;
2335+ return match ? match [ 1 ] : "" ;
2336+ }
22692337 }
22702338 }
22712339
@@ -2431,4 +2499,4 @@ namespace ts {
24312499 export function isCheckJsEnabledForFile ( sourceFile : SourceFile , compilerOptions : CompilerOptions ) {
24322500 return sourceFile . checkJsDirective ? sourceFile . checkJsDirective . enabled : compilerOptions . checkJs ;
24332501 }
2434- }
2502+ }
0 commit comments