import { extractICSS } from 'icss-utils' ; import * as ts_module from 'typescript/lib/tsserverlibrary' ; import * as path from 'path' ; import * as postcss from 'postcss' ; import * as postcssIcssSelectors from 'postcss-icss-selectors' ; export = function init ( { typescript : ts } ) { function isCSS ( fileName ) { return /\.css$/ . test ( fileName ) ; } function isRelativeCSS ( fileName ) { return isCSS ( fileName ) && /^\.\.?($|[\\/])/ . test ( fileName ) ; } function create ( info ) { const processor = postcss ( postcssIcssSelectors ( { mode : 'local' } ) ) ; function getDtsSnapshot ( scriptSnapshot ) { const css = scriptSnapshot . getText ( 0 , scriptSnapshot . getLength ( ) ) ; const dts = Object . keys ( extractICSS ( processor . process ( css ) . root ) . icssExports ) . map ( exportName => `export const ${ exportName }: string;` ) . join ( '' ) ; return ts . ScriptSnapshot . fromString ( dts ) ; } const clssf = ts . createLanguageServiceSourceFile ; ts . createLanguageServiceSourceFile = ( fileName , scriptSnapshot , scriptTarget , version , setNodeParents , scriptKind ? , cheat ? ) : ts . SourceFile => { if ( isCSS ( fileName ) ) { scriptSnapshot = getDtsSnapshot ( scriptSnapshot ) ; } var sourceFile = clssf ( fileName , scriptSnapshot , scriptTarget , version , setNodeParents , scriptKind ) ; if ( isCSS ( fileName ) ) { sourceFile . isDeclarationFile = true ; } return sourceFile ; } ; const ulssf = ts . updateLanguageServiceSourceFile ; ts . updateLanguageServiceSourceFile = ( sourceFile , scriptSnapshot , version , textChangeRange , aggressiveChecks ? , cheat ? ) : ts . SourceFile => { if ( isCSS ( sourceFile . fileName ) ) { scriptSnapshot = getDtsSnapshot ( scriptSnapshot ) ; } var sourceFile = ulssf ( sourceFile , scriptSnapshot , version , textChangeRange , aggressiveChecks ) ; if ( isCSS ( sourceFile . fileName ) ) { sourceFile . isDeclarationFile = true ; } return sourceFile ; } ; if ( info . languageServiceHost . resolveModuleNames ) { const rmn = info . languageServiceHost . resolveModuleNames . bind ( info . languageServiceHost ) ; info . languageServiceHost . resolveModuleNames = ( moduleNames , containingFile , reusedNames ) => { const resolvedCSS = [ ] ; return rmn ( moduleNames . filter ( moduleName => { if ( isRelativeCSS ( moduleName ) ) { resolvedCSS . push ( { resolvedFileName : path . resolve ( path . dirname ( containingFile ) , moduleName ) , extension : ts_module . Extension . Dts , } ) ; return false ; } return true ; } ) , containingFile , reusedNames ) . concat ( resolvedCSS ) ; } ; } return info . languageService ; } function getExternalFiles ( project ) { return project . getFileNames ( ) . filter ( isCSS ) ; } return { create , getExternalFiles } ; } ;