'use strict' ; import cp = require ( 'child_process' ) ; const commandExistsSync = require ( 'command-exists' ) . sync ; import * as vscode from 'vscode' ; import { promptForInstall } from './install-opa' ; import { getImports , getPackage } from './util' ; import { existsSync } from 'fs' ; import { dirname } from 'path' ; var regoVarPattern = new RegExp ( '^[a-zA-Z_][a-zA-Z0-9_]*$' ) ; export function getDataDir ( uri ) { if ( ! installedOPASameOrNewerThan ( "0.14.0-dev" ) ) { return uri . fsPath ; } if ( uri . scheme === "file" ) { return uri . toString ( ) ; } return decodeURIComponent ( uri . toString ( ) ) ; } export function canUseBundleFlags ( ) { let bundleMode = vscode . workspace . getConfiguration ( 'opa' ) . get < boolean > ( 'bundleMode' , true ) ; return installedOPASameOrNewerThan ( "0.14.0-dev" ) && bundleMode ; } function dataFlag ( ) { if ( canUseBundleFlags ( ) ) { return "--bundle" ; } return "--data" ; } function installedOPASameOrNewerThan ( x ) { const s = getOPAVersionString ( ) ; return opaVersionSameOrNewerThan ( s , x ) ; } export function getRoots ( ) { const roots = vscode . workspace . getConfiguration ( 'opa' ) . get < string [ ] > ( 'roots' , [ ] ) ; let formattedRoots = new Array ( ) ; roots . forEach ( root => { root = root . replace ( '${workspaceFolder}' , vscode . workspace . workspaceFolders ! [ 0 ] . uri . toString ( ) ) ; root = root . replace ( '${fileDirname}' , dirname ( vscode . window . activeTextEditor ! . document . fileName ) ) ; formattedRoots . push ( getDataDir ( vscode . Uri . parse ( root ) ) ) ; } ) ; return formattedRoots ; } export function getRootParams ( ) { const flag = dataFlag ( ) ; const roots = getRoots ( ) ; let params = new Array ( ) ; roots . forEach ( root => { params . push ( `${ flag }=${ root }` ) ; } ) ; return params ; } export function getSchemaParams ( ) { let schemaPath = vscode . workspace . getConfiguration ( 'opa' ) . get < string > ( 'schema' ) ; if ( schemaPath === undefined || schemaPath === null ) { return [ ] ; } schemaPath = schemaPath . replace ( '${workspaceFolder}' , vscode . workspace . workspaceFolders ! [ 0 ] . uri . fsPath . toString ( ) ) ; schemaPath = schemaPath . replace ( '${fileDirname}' , dirname ( vscode . window . activeTextEditor ! . document . fileName ) ) ; return [ `--schema=${ schemaPath }` ] ; } function opaVersionSameOrNewerThan ( a , b ) { const aVersion = parseOPAVersion ( a ) ; const bVersion = parseOPAVersion ( b ) ; if ( aVersion . length !== 4 || bVersion . length !== 4 ) { return true ; } for ( let i = 0 ; i < 3 ; i ++ ) { if ( aVersion [ i ] > bVersion [ i ] ) { return true ; } else if ( bVersion [ i ] > aVersion [ i ] ) { return false ; } } if ( aVersion [ 3 ] === '' && bVersion [ 3 ] !== '' ) { return true ; } else if ( aVersion [ 3 ] !== '' && bVersion [ 3 ] === '' ) { return false ; } return aVersion [ 3 ] >= bVersion [ 3 ] ; } function parseOPAVersion ( s ) { const parts = s . split ( '.' , 3 ) ; if ( parts . length < 3 ) { return [ ] ; } const major = Number ( parts [ 0 ] ) ; const minor = Number ( parts [ 1 ] ) ; const pointParts = parts [ 2 ] . split ( '-' , 2 ) ; const point = Number ( pointParts [ 0 ] ) ; let patch = '' ; if ( pointParts . length >= 2 ) { patch = pointParts [ 1 ] ; } return [ major , minor , point , patch ] ; } function getOPAVersionString ( ) { const result = cp . spawnSync ( 'opa' , [ 'version' ] ) ; if ( result . status !== 0 ) { return '' ; } const lines = result . stdout . toString ( ) . split ( '\n' ) ; for ( let i = 0 ; i < lines . length ; i ++ ) { const parts = lines [ i ] . trim ( ) . split ( ': ' , 2 ) ; if ( parts . length < 2 ) { continue ; } if ( parts [ 0 ] === 'Version' ) { return parts [ 1 ] ; } } return '' ; } export function refToString ( ref ) { let result = ref [ 0 ] . value ; for ( let i = 1 ; i < ref . length ; i ++ ) { if ( ref [ i ] . type === "string" ) { if ( regoVarPattern . test ( ref [ i ] . value ) ) { result += '.' + ref [ i ] . value ; continue ; } } result += '[' + JSON . stringify ( ref [ i ] . value ) + ']' ; } return result ; } /**
 * Helpers for executing OPA as a subprocess.
 */ export function parse ( opaPath , path , cb , onerror ) { run ( opaPath , [ 'parse' , path , '--format' , 'json' ] , '' , ( _ , result ) => { let pkg = getPackage ( result ) ; let imports = getImports ( result ) ; cb ( pkg , imports ) ; } , onerror ) ; } export function run ( path , args , stdin , onSuccess , onFailure ) { runWithStatus ( path , args , stdin , ( code , stderr , stdout ) => { if ( code === 0 ) { onSuccess ( stderr , JSON . parse ( stdout ) ) ; } else if ( stdout !== '' ) { onFailure ( stdout ) ; } else { onFailure ( stderr ) ; } } ) ; } export function runWithStatus ( path , args , stdin , cb ) { let opaPath = vscode . workspace . getConfiguration ( 'opa' ) . get < string > ( 'path' ) ; if ( opaPath !== undefined && opaPath !== null ) { opaPath = opaPath . replace ( '${workspaceFolder}' , vscode . workspace . workspaceFolders ! [ 0 ] . uri . fsPath . toString ( ) ) ; } const existsOnPath = commandExistsSync ( path ) ; const existsInUserSettings = opaPath !== undefined && opaPath !== null && existsSync ( opaPath ) ; if ( ! ( existsOnPath || existsInUserSettings ) ) { promptForInstall ( ) ; return ; } if ( existsInUserSettings && opaPath !== undefined ) { path = opaPath ; } console . log ( "spawn:" , path , "args:" , args . toString ( ) ) ; let proc = cp . spawn ( path , args ) ; proc . stdin . write ( stdin ) ; proc . stdin . end ( ) ; let stdout = "" ; let stderr = "" ; proc . stdout . on ( 'data' , ( data ) => { stdout += data ; } ) ; proc . stderr . on ( 'data' , ( data ) => { stderr += data ; } ) ; proc . on ( 'exit' , ( code , signal ) => { console . log ( "code:" , code ) ; console . log ( "stdout:" , stdout ) ; console . log ( "stderr:" , stderr ) ; cb ( code , stderr , stdout ) ; } ) ; }