import * as path from 'path' ; import * as protobufjs from 'protobufjs' ; if ( typeof global . gc !== 'function' ) { require ( 'v8' ) . setFlagsFromString ( '--expose_gc' ) ; global . gc = require ( 'vm' ) . runInNewContext ( 'gc' ) ; } /**
 * Whether to print debug messages (to console.error) from the debug function
 * below.
 */ export const DEBUG = false ; /** Maybe print a debug message (depending on a flag defaulting to false). */ export function debug ( ... args ) { if ( DEBUG ) console . error . call ( console , ... args ) ; } /**
 * Write a message to stderr, which appears in the bazel log and is visible to
 * the end user.
 */ export function log ( ... args ) { console . error . call ( console , ... args ) ; } /**
 * runAsWorker returns true if the given arguments indicate the process should
 * run as a persistent worker.
 */ export function runAsWorker ( args ) { return args . indexOf ( '--persistent_worker' ) !== - 1 ; } /**
 * workerProto declares the static type of the object constructed at runtime by
 * protobufjs, based on reading the protocol buffer definition.
 */ declare namespace workerProto { /** Input represents the blaze.worker.Input message. */ interface Input extends protobufjs . Message < Input > { path : string ; /**
         * In Node, digest is a Buffer. In the browser, it's a replacement
         * implementation. We only care about its toString(encoding) method.
         */ digest : { toString ( encoding ) : string ; } ; } /** WorkRequest repesents the blaze.worker.WorkRequest message. */ interface WorkRequest extends protobufjs . Message < WorkRequest > { arguments : string [ ] ; inputs : Input [ ] ; } const WorkRequest ; const WorkResponse ; } /**
 * loadWorkerPb finds and loads the protocol buffer definition for bazel's
 * worker protocol using protobufjs. In protobufjs, this means it's a reflection
 * object that also contains properties for the individual messages.
 */ function loadWorkerPb ( ) { const protoPath = '../../third_party/github.com/bazelbuild/bazel/src/main/protobuf/worker_protocol.proto' ; let protofile ; try { protofile = require . resolve ( protoPath ) ; } catch ( e ) { } if ( ! protofile ) { const runfiles = process . env [ 'BAZEL_NODE_RUNFILES_HELPER' ] ; if ( runfiles ) { protofile = require ( runfiles ) . resolve ( 'build_bazel_rules_typescript/third_party/github.com/bazelbuild/bazel/src/main/protobuf/worker_protocol.proto' ) ; } if ( ! protofile ) { throw new Error ( `cannot find worker_protocol.proto at ${ protoPath } or in Runfiles` ) ; } } const protoNamespace = protobufjs . loadSync ( protofile ) ; if ( ! protoNamespace ) { throw new Error ( 'Cannot find ' + path . resolve ( protoPath ) ) ; } const workerpb = protoNamespace . lookup ( 'blaze.worker' ) ; if ( ! workerpb ) { throw new Error ( `Cannot find namespace blaze.worker` ) ; } return workerpb as protobufjs . ReflectionObject & typeof workerProto ; } /**
 * workerpb contains the runtime representation of the worker protocol buffer,
 * including accessor for the defined messages.
 */ const workerpb = loadWorkerPb ( ) ; /**
 * runWorkerLoop handles the interacton between bazel workers and the
 * TypeScript compiler. It reads compilation requests from stdin, unmarshals the
 * data, and dispatches into `runOneBuild` for the actual compilation to happen.
 *
 * The compilation handler is parameterized so that this code can be used by
 * different compiler entry points (currently TypeScript compilation, Angular
 * compilation, and the contrib vulcanize worker).
 *
 * It's also exposed publicly as an npm package:
 *   https://www.npmjs.com/package/@bazel/worker
 */ export async function runWorkerLoop ( runOneBuild ) { let consoleOutput = '' ; process . stderr . write = ( chunk , ... otherArgs ) : boolean => { consoleOutput += chunk . toString ( ) ; return true ; } ; let buf = Buffer . alloc ( 0 ) ; stdinLoop : for await ( const chunk of process . stdin ) { buf = Buffer . concat ( [ buf , chunk as Buffer ] ) ; try { const reader = new protobufjs . Reader ( buf ) ; while ( reader . len - reader . pos > 0 ) { const messageStart = reader . len ; const msgLength = reader . uint32 ( ) ; if ( ( reader . len - reader . pos ) < msgLength ) continue stdinLoop ; const req = workerpb . WorkRequest . decode ( reader , msgLength ) as workerProto . WorkRequest ; buf = buf . slice ( messageStart ) ; debug ( '=== Handling new build request' ) ; consoleOutput = '' ; const args = req . arguments ; const inputs = { } ; for ( const input of req . inputs ) { inputs [ input . path ] = input . digest . toString ( 'hex' ) ; } debug ( 'Compiling with:\n\t' + args . join ( '\n\t' ) ) ; const exitCode = ( await runOneBuild ( args , inputs ) ) ? 0 : 1 ; process . stdout . write ( ( workerpb . WorkResponse . encodeDelimited ( { exitCode , output : consoleOutput } ) ) . finish ( ) as Buffer ) ; global . gc ( ) ; } if ( buf . length > 0 ) { throw new Error ( 'buffer not empty after reading all messages' ) ; } } catch ( e ) { log ( 'Compilation failed' , e . stack ) ; process . stdout . write ( workerpb . WorkResponse . encodeDelimited ( { exitCode : 1 , output : consoleOutput } ) . finish ( ) as Buffer ) ; buf = Buffer . alloc ( 0 ) ; } } }