'use strict' ; import * as cp from 'child_process' ; import * as fs from 'fs' ; import * as os from 'os' ; import * as path from 'path' ; import * as vscode from 'vscode' ; const findCfg = checkPath => { try { fs . accessSync ( path . join ( checkPath , '.rubocop.yml' ) ) ; return checkPath ; } catch ( e ) { let nextCheckPath = path . dirname ( checkPath ) ; if ( nextCheckPath && nextCheckPath !== checkPath ) return findCfg ( nextCheckPath ) ; } } ; export class AutoCorrect { get opts ( ) : any { const opts = vscode . workspace . getConfiguration ( 'ruby.lint.rubocop' ) ; if ( ! opts || opts === true ) { return { } ; } return opts ; } get exe ( ) : string [ ] { const opts = this . opts ; if ( opts . exe ) { return [ opts . exe ] ; } const ext = process . platform === 'win32' ? '.bat' : '' ; if ( vscode . workspace . getConfiguration ( 'ruby' ) . useBundler ) { const pathToBundler = vscode . workspace . getConfiguration ( 'ruby' ) . pathToBundler || 'bundle' ; return [ `${ pathToBundler }${ ext }` , 'exec' , 'rubocop' ] ; } return [ `rubocop${ ext }` ] ; } args = ( root ) : string [ ] => { let args = [ '-a' , '-f' , 'simple' ] ; if ( root ) { const cfgPath = findCfg ( root ) ; if ( cfgPath ) { args = args . concat ( [ '-c' , path . join ( cfgPath , '.rubocop.yml' ) ] ) ; } } const opts = this . opts ; if ( opts . lint ) { args . push ( '-l' ) ; } if ( opts . only ) { args = args . concat ( '--only' , opts . only . join ( ',' ) ) ; } if ( opts . except ) { args = args . concat ( '--except' , opts . except . join ( ',' ) ) ; } if ( opts . rails ) { args . push ( '-R' ) ; } if ( opts . require ) { args = args . concat ( '-r' , opts . require . join ( ',' ) ) ; } return args ; } ; private spawn = ( args , options ? ) : cp . ChildProcess => { const exe = this . exe ; const spawnOpt = options ? options : { } ; if ( ! spawnOpt . cwd ) { spawnOpt . cwd = vscode . workspace . rootPath ; } return cp . spawn ( exe . shift ( ) , exe . concat ( args ) , spawnOpt ) ; } ; public test ( ) { return new Promise ( ( resolve , reject ) => { const rubo = this . spawn ( [ '-v' ] ) ; rubo . on ( 'error' , err => { if ( err . message . includes ( 'ENOENT' ) ) { vscode . window . showErrorMessage ( `couldn't find ${ this . exe } for formatting (ENOENT)` ) ; } else { vscode . window . showErrorMessage ( `couldn't run ${ this . exe } '${ err . message }'` ) ; } reject ( err ) ; } ) ; rubo . stderr . on ( 'data' , data => { console . log ( `rubocop stderr ${ data }` ) ; } ) ; rubo . stdout . on ( 'data' , data => { console . log ( `rubocop stdout ${ data }` ) ; } ) ; rubo . on ( 'exit' , code => { if ( code ) { vscode . window . showErrorMessage ( `rubocop failed with code=${ code }` ) ; return reject ( ) ; } console . log ( `rubocop is ready to go!` ) ; resolve ( ) ; } ) ; } ) ; } public correct ( data , root ) { return new Promise ( ( resolve , reject ) => fs . mkdtemp ( path . join ( os . tmpdir ( ) , 'rubocop' ) , ( err , folder ) => { if ( err ) return reject ( err ) ; const args = this . args ( root ) ; const tmpfile = path . join ( folder , 'tmp.rb' ) ; args . push ( tmpfile ) ; fs . writeFile ( tmpfile , data , err => { if ( err ) return reject ( err ) ; console . log ( `${ this . exe } ${ args . join ( ' ' ) }` ) ; const startTm = new Date ( ) . getTime ( ) ; const rubo = this . spawn ( args , { cwd : root || process . cwd ( ) , env : process . env , } ) ; rubo . on ( 'error' , error => { vscode . window . showErrorMessage ( `couldn't run rubocop '${ error . message }'` ) ; reject ( error ) ; } ) ; rubo . stderr . on ( 'data' , data => { console . log ( `rubocop stderr ${ data }` ) ; } ) ; rubo . on ( 'exit' , code => { if ( code && code !== 1 ) { vscode . window . showErrorMessage ( `rubocop failed with code=${ code }` ) ; return reject ( ) ; } fs . readFile ( tmpfile , 'utf8' , ( err , result ) => { if ( err ) reject ( err ) ; const elapsedTm = new Date ( ) . getTime ( ) - startTm ; console . log ( `rubocop ran in ${ elapsedTm }ms` ) ; resolve ( result ) ; } ) ; } ) ; } ) ; } ) ) ; } }