"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.contentFingerprint=exports.fingerprint=exports.clearLargeFileFingerprintCache=void 0;const crypto=require("crypto"),fs=require("fs"),path=require("path"),cache_1=require("../private/cache"),ignore_1=require("./ignore"),options_1=require("./options"),utils_1=require("./utils"),BUFFER_SIZE=8*1024,CTRL_SOH="",CTRL_SOT="",CTRL_ETX="",CR="\r",LF=`
`,CRLF=`${CR}${LF}`,fingerprintCache=new cache_1.Cache;function clearLargeFileFingerprintCache(){fingerprintCache.clear()}exports.clearLargeFileFingerprintCache=clearLargeFileFingerprintCache;function fingerprint(fileOrDirectory,options={}){const hash=crypto.createHash("sha256");_hashField(hash,"options.extra",options.extraHash||"");const follow=options.follow||options_1.SymlinkFollowMode.EXTERNAL;_hashField(hash,"options.follow",follow),fileOrDirectory=fs.realpathSync(fileOrDirectory);const isDir=fs.statSync(fileOrDirectory).isDirectory(),rootDirectory=isDir?fileOrDirectory:path.dirname(fileOrDirectory),ignoreMode=options.ignoreMode||options_1.IgnoreMode.GLOB;ignoreMode!=options_1.IgnoreMode.GLOB&&_hashField(hash,"options.ignoreMode",ignoreMode);const ignoreStrategy=ignore_1.IgnoreStrategy.fromCopyOptions(options,fileOrDirectory);return _processFileOrDirectory(fileOrDirectory,isDir),hash.digest("hex");function _processFileOrDirectory(symbolicPath,isRootDir=!1,realPath=symbolicPath){if(!isRootDir&&ignoreStrategy.ignores(symbolicPath))return;const stat=fs.lstatSync(realPath),hashComponent=path.relative(fileOrDirectory,symbolicPath).replace(/\\/g,"/");if(stat.isSymbolicLink()){const linkTarget=fs.readlinkSync(realPath),resolvedLinkTarget=path.resolve(path.dirname(realPath),linkTarget);utils_1.shouldFollow(follow,rootDirectory,resolvedLinkTarget)?_processFileOrDirectory(symbolicPath,!1,resolvedLinkTarget):_hashField(hash,`link:${hashComponent}`,linkTarget)}else if(stat.isFile())_hashField(hash,`file:${hashComponent}`,contentFingerprint(realPath));else if(stat.isDirectory())for(const item of fs.readdirSync(realPath).sort())_processFileOrDirectory(path.join(symbolicPath,item),!1,path.join(realPath,item));else throw new Error(`Unable to hash ${symbolicPath}: it is neither a file nor a directory`)}}exports.fingerprint=fingerprint;function contentFingerprint(file){const stats=fs.statSync(file,{bigint:!0}),cacheKey=JSON.stringify({mtime_unix:stats.mtime.toUTCString(),mtime_ms:stats.mtimeMs.toString(),inode:stats.ino.toString(),size:stats.size.toString()});return fingerprintCache.obtain(cacheKey,()=>contentFingerprintMiss(file))}exports.contentFingerprint=contentFingerprint;function contentFingerprintMiss(file){const hash=crypto.createHash("sha256"),buffer=Buffer.alloc(BUFFER_SIZE),fd=fs.openSync(file,fs.constants.O_DSYNC|fs.constants.O_RDONLY|fs.constants.O_SYNC);let size=0,isBinary=!1,lastStr="",read=0;try{for(;(read=fs.readSync(fd,buffer,0,BUFFER_SIZE,null))!==0;){const slicedBuffer=buffer.slice(0,read);size===0&&(isBinary=slicedBuffer.indexOf(0)!==-1);let dataBuffer=slicedBuffer;if(!isBinary){const str=buffer.slice(0,read).toString();if(new RegExp(`${CR}$`).test(str)){lastStr+=str;continue}const normalizedData=(lastStr+str).replace(new RegExp(CRLF,"g"),LF);dataBuffer=Buffer.from(normalizedData),lastStr=""}size+=dataBuffer.length,hash.update(dataBuffer)}lastStr&&hash.update(Buffer.from(lastStr))}finally{fs.closeSync(fd)}return`${size}:${hash.digest("hex")}`}function _hashField(hash,header,value){hash.update(CTRL_SOH).update(header).update(CTRL_SOT).update(value).update(CTRL_ETX)}
//# sourceMappingURL=fingerprint.js.map
