text: const fs = require( 'fs' );
  const path = require( 'path' );
  
  // Replace unneeded function definitions and checks. The `continueGeneration` block is always at the top of
  // a function definition so we can replace that with local variable definitions we need.
  function replaceUnneededCode( str ) {
  
  	str = str.replace(
  		/if \( node.continueGeneration \)(.|\n|\r)*?}[\r|\n]/mg,
  		'const stride2Offset = stride4Offset * 2, ' +
  		'float32Array = _float32Array, ' +
  		'uint16Array = _uint16Array, ' +
  		'uint32Array = _uint32Array;'
  	);
  
  	str = str.replace( /function intersectRay\((.|[\r|\n])*?}[\r|\n]/mg, '' );
  
  	str = str.replace( /import { arrayToBox.*?;[\r|\n]/g, '' );
  
  	return str;
  
  }
  
  // Replace function calls with buffer variants defined in the added functions.
  function replaceFunctionCalls( str ) {
  
  	str = str.replace( /arrayToBox\((.*?),/g, ( match, arg ) => {
  
  		return `arrayToBoxBuffer(${ arg }, float32Array,`;
  
  	} );
  
  	str = str.replace( /intersectRay\((.*?),/g, ( match, arg ) => {
  
  		return `intersectRayBuffer(${ arg }, float32Array,`;
  
  	} );
  
  	return str;
  
  }
  
  function replaceNodeNames( str ) {
  
  	const convertName = ( name, count = 4 ) => {
  
  		return name === 'node' ? `stride${ count }Offset` : name;
  
  	};
  
  	const names = 'c1|c2|left|right|node';
  
  
  	str = str.replace(
  		new RegExp( `(${ names })\\.boundingData\\[(.*)\\]\\[(.*)\\]`, 'g' ),
  		( match, name, index, index2 ) => `/* ${ name } boundingData */ float32Array[ ${ convertName( name ) } +${ index }+${ index2 }]`
  	);
  
  	str = str.replace(
  		new RegExp( `(${ names })\\.boundingData\\[(.*)\\]`, 'g' ),
  		( match, name, index ) => `/* ${ name } boundingData */ float32Array[ ${ convertName( name ) } +${ index }]`
  	);
  
  	str = str.replace(
  		new RegExp( `(${ names })\\.boundingData`, 'g' ),
  		( match, name ) => `/* ${ name } boundingData */ ${ convertName( name ) }`
  	);
  
  	str = str.replace(
  		new RegExp( `(${ names })\\.offset`, 'g' ),
  		( match, name ) => `/* ${ name } offset */ uint32Array[ ${ convertName( name ) } + 6 ]`
  	);
  
  	str = str.replace(
  		new RegExp( `! ! (${ names })\\.count`, 'g' ),
  		( match, name ) => `/* ${ name } count */ uint16Array[ ${ convertName( name, 2 ) } + 15 ] === 0xffff`
  	);
  
  	str = str.replace(
  		new RegExp( `(${ names })\\.count`, 'g' ),
  		( match, name ) => `/* ${ name } count */ uint16Array[ ${ convertName( name, 2 ) } + 14 ]`
  	);
  
  	str = str.replace(
  		new RegExp( `(${ names })\\.left`, 'g' ),
  		( match, name ) => `/* ${ name } left */ ${ convertName( name ) } + 8`
  	);
  
  	str = str.replace(
  		new RegExp( `(${ names })\\.right`, 'g' ),
  		( match, name ) => `/* ${ name } right */ uint32Array[ ${ convertName( name ) } + 6 ]`
  	);
  
  	str = str.replace(
  		new RegExp( `(${ names })\\.splitAxis`, 'g' ),
  		( match, name ) => `/* ${ name } splitAxis */ uint32Array[ ${ convertName( name ) } + 7 ]`
  	);
  
  	return str;
  
  }
  
  function replaceFunctionNames( str ) {
  
  	const orNames = '\\s(raycast|raycastFirst|shapecast|intersectsGeometry)';
  
  	str = str.replace(
  		new RegExp( `(${ orNames })\\((\\s|[\\r|\\n])?node`, 'gm' ),
  		( match, funcName ) => {
  
  			return `${ funcName }Buffer( stride4Offset`;
  
  		}
  	);
  
  	str = str.replace(
  		new RegExp( `(${ orNames })\\(`, 'gm' ),
  		( match, funcName ) => {
  
  			return `${ funcName }Buffer(`;
  
  		}
  	);
  
  	str = str.replace(
  		new RegExp( `const(${ orNames })`, 'gm' ),
  		( match, funcName ) => {
  
  			return `const${ funcName }Buffer`;
  
  		}
  	);
  
  	return str;
  
  }
  
  function addFunctions( str ) {
  
  	str = str + `
  
  function intersectRayBuffer( stride4Offset, array, ray, target ) {
  
  	arrayToBoxBuffer( stride4Offset, array, boundingBox );
  	return ray.intersectBox( boundingBox, target );
  
  }
  
  const bufferStack = [];
  let _prevBuffer;
  let _float32Array;
  let _uint16Array;
  let _uint32Array;
  export function setBuffer( buffer ) {
  
  	if ( _prevBuffer ) {
  
  		bufferStack.push( _prevBuffer );
  
  	}
  
  	_prevBuffer = buffer;
  	_float32Array = new Float32Array( buffer );
  	_uint16Array = new Uint16Array( buffer );
  	_uint32Array = new Uint32Array( buffer );
  
  }
  
  export function clearBuffer() {
  
  	_prevBuffer = null;
  	_float32Array = null;
  	_uint16Array = null;
  	_uint32Array = null;
  
  	if ( bufferStack.length ) {
  
  		setBuffer( bufferStack.pop() );
  
  	}
  
  }
  
  function arrayToBoxBuffer( stride4Offset, array, target ) {
  
  	target.min.x = array[ stride4Offset ];
  	target.min.y = array[ stride4Offset + 1 ];
  	target.min.z = array[ stride4Offset + 2 ];
  
  	target.max.x = array[ stride4Offset + 3 ];
  	target.max.y = array[ stride4Offset + 4 ];
  	target.max.z = array[ stride4Offset + 5 ];
  
  }
  `;
  
  	return str;
  
  }
  
  function addHeaderComment( str ) {
  
  	str = `
  /**************************************************************************************************
   *
   * This file is generated from castFunctions.js and scripts/generate-cast-function.mjs. Do not edit.
   *
   *************************************************************************************************/
  ` + str;
  
  	return str;
  
  }
  
  const templatePath = path.resolve( './src/castFunctions.js' );
  const bufferFilePath = path.resolve( './src/castFunctionsBuffer.js' );
  const str = fs.readFileSync( templatePath, { encoding: 'utf8' } );
  
  let result = str;
  result = replaceUnneededCode( result );
  result = replaceFunctionCalls( result );
  result = replaceNodeNames( result );
  result = replaceFunctionNames( result );
  result = addFunctions( result );
  result = addHeaderComment( result );
  fs.writeFileSync( bufferFilePath, result );
  