license import 'jasmine' ; import * as ts from 'typescript' ; import { checkModuleDeps } from './strict_deps' ; describe ( 'strict deps' , ( ) => { const astCache = new Map < string , ts . SourceFile > ( ) ; function createProgram ( files ) { const options = { noResolve : true , baseUrl : '/src' , rootDirs : [ '/src' , '/src/blaze-bin' ] , paths : { '*' : [ '*' , 'blaze-bin/*' ] } } ; const host = ts . createCompilerHost ( options ) ; const originalGetSourceFile = host . getSourceFile . bind ( host ) ; host . getSourceFile = ( fileName ) => { if ( ! files [ fileName ] ) { if ( astCache . has ( fileName ) ) return astCache . get ( fileName ) ; const file = originalGetSourceFile ( fileName , ts . ScriptTarget . Latest ) ; astCache . set ( fileName , file ! ) ; return file ; } return ts . createSourceFile ( fileName , files [ fileName ] , ts . ScriptTarget . Latest ) ; } ; host . fileExists = ( f ) => ! ! files [ f ] ; host . directoryExists = ( ) => true ; host . realpath = ( f ) => f ; const rf = host . readFile . bind ( host ) ; host . readFile = ( f ) => files [ f ] || rf ( f ) ; host . getCurrentDirectory = ( ) => '/src' ; host . getDirectories = ( path ) => [ ] ; const p = ts . createProgram ( Object . keys ( files ) , options , host ) ; const diags = [ ... ts . getPreEmitDiagnostics ( p ) ] ; if ( diags . length > 0 ) { throw new Error ( ts . formatDiagnostics ( diags , { getCurrentDirectory : ( ) => ts . sys . getCurrentDirectory ( ) , getNewLine : ( ) => ts . sys . newLine , getCanonicalFileName : ( f ) => f } ) ) ; } return p ; } it ( 'reports errors for transitive dependencies' , ( ) => { const p = createProgram ( { '/src/p/sd1.ts' : 'export let x = 1;' , '/src/p/sd2.ts' : `import {x} from "./sd1";
          export let y = x;` , '/src/p/sd3.ts' : `import {y} from "./sd2";
          import {x} from "./sd1";
          export let z = x + y;` } ) ; const diags = checkModuleDeps ( p . getSourceFile ( 'p/sd3.ts' ) ! , p . getTypeChecker ( ) , [ '/src/p/sd2.ts' ] , '/src' ) ; expect ( diags . length ) . toBe ( 1 ) ; expect ( diags [ 0 ] . messageText ) . toMatch ( /transitive dependency on p\/sd1.ts not allowed/ ) ; } ) ; it ( 'reports errors for exports' , ( ) => { const p = createProgram ( { '/src/p/sd1.ts' : 'export let x = 1;' , '/src/p/sd2.ts' : `import {x} from "./sd1";
          export let y = x;` , '/src/p/sd3.ts' : `export {x} from "./sd1";` } ) ; const diags = checkModuleDeps ( p . getSourceFile ( 'p/sd3.ts' ) ! , p . getTypeChecker ( ) , [ '/src/p/sd2.ts' ] , '/src' ) ; expect ( diags . length ) . toBe ( 1 ) ; expect ( diags [ 0 ] . messageText ) . toMatch ( /transitive dependency on p\/sd1.ts not allowed/ ) ; } ) ; it ( 'supports files mapped in blaze-bin' , ( ) => { const p = createProgram ( { '/src/blaze-bin/p/sd1.ts' : 'export let x = 1;' , '/src/blaze-bin/p/sd2.ts' : `import {x} from "./sd1";
          export let y = x;` , '/src/p/sd3.ts' : `import {y} from "./sd2";
          import {x} from "./sd1";
          export let z = x + y;` } ) ; const diags = checkModuleDeps ( p . getSourceFile ( '/src/p/sd3.ts' ) ! , p . getTypeChecker ( ) , [ '/src/blaze-bin/p/sd2.ts' ] , '/src' ) ; expect ( diags . length ) . toBe ( 1 ) ; expect ( diags [ 0 ] . messageText ) . toMatch ( /dependency on blaze-bin\/p\/sd1.ts not allowed/ ) ; } ) ; it ( 'supports .d.ts files' , ( ) => { const p = createProgram ( { '/src/blaze-bin/p/sd1.d.ts' : 'export declare let x: number;' , '/src/blaze-bin/p/sd2.d.ts' : `import {x} from "./sd1";
          export declare let y: number;` , '/src/p/sd3.ts' : `import {y} from "./sd2";
          import {x} from "./sd1";
          export let z = x + y;` } ) ; const diags = checkModuleDeps ( p . getSourceFile ( '/src/p/sd3.ts' ) ! , p . getTypeChecker ( ) , [ '/src/blaze-bin/p/sd2.d.ts' ] , '/src' ) ; expect ( diags . length ) . toBe ( 1 ) ; expect ( diags [ 0 ] . messageText ) . toMatch ( /dependency on blaze-bin\/p\/sd1.d.ts not allowed/ ) ; } ) ; it ( 'allows multiple declarations of the same clutz-generated module' , ( ) => { const p = createProgram ( { '/src/blaze-bin/p/js1.d.ts' : `declare module 'goog:thing' {}` , '/src/blaze-bin/p/js2.d.ts' : `declare module 'goog:thing' {}` , '/src/blaze-bin/p/js3.d.ts' : `declare module 'goog:thing' {}` , '/src/p/my.ts' : `import {} from 'goog:thing'; // taze: from //p:js2` } ) ; const good = checkModuleDeps ( p . getSourceFile ( '/src/p/my.ts' ) ! , p . getTypeChecker ( ) , [ '/src/blaze-bin/p/js2.d.ts' ] , '/src' ) ; expect ( good . length ) . toBe ( 0 ) ; const bad = checkModuleDeps ( p . getSourceFile ( '/src/p/my.ts' ) ! , p . getTypeChecker ( ) , [ ] , '/src' ) ; expect ( bad . length ) . toBe ( 1 ) ; expect ( bad [ 0 ] . messageText ) . toContain ( '(It is also declared in blaze-bin/p/js2.d.ts, blaze-bin/p/js3.d.ts)' ) ; } ) ; } ) ;