@zipbul/gildash 0.8.1 → 0.8.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +0 -3
- package/package.json +2 -2
- package/dist/index.js.map +0 -58
package/dist/index.js
CHANGED
|
@@ -5,6 +5,3 @@ var Ig=Object.defineProperty;var kg=(n)=>n;function Cg(n,u){this[n]=kg.bind(null
|
|
|
5
5
|
`).length})}let L=new Set;for(let U of M)for(let[W]of m.getFilesMap(U.project))L.add(`${U.project}::${W}`);let C=this.opts.parseSourceFn??$n;for(let U of H){let W=G(U.filePath,M),R=C(_n(r,U.filePath),U.text);if(Iu(R))throw R.data;let X=R;Z.push({filePath:U.filePath,parsed:X}),hn({parsed:X,project:W,filePath:U.filePath,contentHash:U.contentHash,symbolRepo:i}),Y+=on({ast:X.program,project:W,filePath:U.filePath,relationRepo:t,projectRoot:r,tsconfigPaths:_,knownFiles:L,boundaries:M}),B+=i.getFileSymbols(W,U.filePath).length}});for(let L of Z)D.set(L.filePath,L.parsed)}else{V();let r=await Q();B=r.symbols,Y=r.relations,N=r.failedFiles}for(let r of w){let M=G(r.filePath,this.opts.boundaries);for(let D of i.getFileSymbols(M,r.filePath))z.set(`${D.filePath}::${D.name}`,{name:D.name,filePath:D.filePath,kind:D.kind,fingerprint:D.fingerprint})}let $={added:[],modified:[],removed:[]};for(let[r,M]of z){let D=f.get(r);if(!D)$.added.push({name:M.name,filePath:M.filePath,kind:M.kind});else if(D.fingerprint!==M.fingerprint)$.modified.push({name:M.name,filePath:M.filePath,kind:M.kind})}for(let[r,M]of f)if(!z.has(r))$.removed.push({name:M.name,filePath:M.filePath,kind:M.kind});if(!u)for(let[r,M]of A)for(let D of M){if(!D.fingerprint)continue;let H=G(r,this.opts.boundaries),Z=i.getByFingerprint(H,D.fingerprint);if(Z.length===1){let L=Z[0];t.retargetRelations({dstProject:H,oldFile:r,oldSymbol:D.name,newFile:L.filePath,newSymbol:L.name})}}return{indexedFiles:w.length,removedFiles:O.length,totalSymbols:B,totalRelations:Y,durationMs:Date.now()-g,changedFiles:w.map((r)=>r.filePath),deletedFiles:[...O],failedFiles:N,changedSymbols:$}}fireCallbacks(n){for(let u of this.callbacks)try{u(n)}catch(g){this.logger.error("[IndexCoordinator] onIndexed callback threw:",g)}}flushPending(){if(this.indexingLock)return;if(this.pendingEvents.length>0){let n=this.pendingEvents.splice(0);this.startIndex(n,!1).catch((u)=>this.logger.error("[IndexCoordinator] flushPending startIndex error:",u))}}}function Nm(n){try{return process.kill(n,0),!0}catch(u){if(typeof u==="object"&&u&&"code"in u)return u.code!=="ESRCH";return!0}}function Mm(n){let u=new Date(n).getTime();return Number.isNaN(u)?0:u}function Cu(n,u,g={}){let m=g.now??Date.now,i=g.isAlive??Nm,t=g.staleAfterSeconds??60,S=g.instanceId;return n.immediateTransaction(()=>{let w=n.selectOwner();if(!w)return n.insertOwner(u,S),"owner";let O=Math.floor((m()-Mm(w.heartbeat_at))/1000),_=i(w.pid);if(_&&S&&w.instance_id&&w.instance_id!==S&&w.pid!==u)return n.replaceOwner(u,S),"owner";if(_&&O<t)return"reader";return n.replaceOwner(u,S),"owner"})}function Tu(n,u){n.deleteOwner(u)}function yu(n,u){n.touchOwner(u)}class zn{#n;#u=new Map;constructor(n){this.#n=Math.max(1,n)}get size(){return this.#u.size}has(n){return this.#u.has(n)}get(n){if(!this.#u.has(n))return;let u=this.#u.get(n);return this.#u.delete(n),this.#u.set(n,u),u}set(n,u){if(this.#u.has(n))this.#u.delete(n);if(this.#u.set(n,u),this.#u.size>this.#n){let g=this.#u.keys().next().value;if(g!==void 0)this.#u.delete(g)}}delete(n){return this.#u.delete(n)}clear(){this.#u.clear()}}class cn{lru;constructor(n=500){this.lru=new zn(n)}get(n){return this.lru.get(n)}set(n,u){this.lru.set(n,u)}invalidate(n){this.lru.delete(n)}invalidateAll(){this.lru.clear()}size(){return this.lru.size}}function en(n){let{symbolRepo:u,project:g,query:m}=n,i=m.project??g,t=m.limit??100,S={kind:m.kind,filePath:m.filePath,isExported:m.isExported,project:i,limit:t,resolvedType:m.resolvedType};if(m.text)if(m.exact)S.exactName=m.text;else{let O=Qn(m.text);if(O)S.ftsQuery=O}if(m.decorator)S.decorator=m.decorator;if(m.regex)S.regex=m.regex;return u.searchByQuery(S).map((O)=>({id:O.id,filePath:O.filePath,kind:O.kind,name:O.name,span:{start:{line:O.startLine,column:O.startColumn},end:{line:O.endLine,column:O.endColumn}},isExported:O.isExported===1,signature:O.signature,fingerprint:O.fingerprint,detail:O.detailJson?(()=>{try{return JSON.parse(O.detailJson)}catch{return{}}})():{}}))}function nu(n){let{relationRepo:u,project:g,query:m}=n,i=m.project??g,t=m.limit??500;return u.searchRelations({srcFilePath:m.srcFilePath,srcSymbolName:m.srcSymbolName,dstFilePath:m.dstFilePath,dstSymbolName:m.dstSymbolName,dstProject:m.dstProject,type:m.type,project:i,limit:t}).map((w)=>{let O;if(w.metaJson)try{O=JSON.parse(w.metaJson)}catch{}return{type:w.type,srcFilePath:w.srcFilePath,srcSymbolName:w.srcSymbolName,dstFilePath:w.dstFilePath,dstSymbolName:w.dstSymbolName,dstProject:w.dstProject,metaJson:w.metaJson??void 0,meta:O}})}import{findInFiles as $m,Lang as zm}from"@ast-grep/napi";async function uu(n){if(n.filePaths.length===0)return[];let u=[];return await $m(zm.TypeScript,{paths:n.filePaths,matcher:{rule:{pattern:n.pattern}}},(g,m)=>{if(g)return;for(let i of m){let t=i.range();u.push({filePath:i.getRoot().filename(),startLine:t.start.line+1,endLine:t.end.line+1,matchedText:i.text()})}}),u}import b from"typescript";import{isErr as km}from"@zipbul/result";import l from"typescript";import Dm from"path";import{err as gu}from"@zipbul/result";function Km(n){try{return Ju("fs").readFileSync(n,"utf-8")}catch{return}}function Vm(n){try{return Ju("fs").readFileSync(n,"utf-8")}catch{return}}class In{#n;#u;#g=!1;__testing__;constructor(n,u){this.#n=n,this.#u=u,this.__testing__={host:u}}static create(n,u={}){let g=u.readConfigFile??Km,m=u.resolveNonTrackedFile??Vm,i=Dm.dirname(n),t=g(n);if(t===void 0)return gu(p("semantic",`tsconfig not found: ${n}`));let S=l.parseJsonText(n,t),w=S.parseDiagnostics;if(w&&w.length>0){let f=w.map((z)=>l.flattenDiagnosticMessageText(z.messageText,`
|
|
6
6
|
`)).join("; ");return gu(p("semantic",`tsconfig parse error: ${f}`))}let O=l.parseJsonSourceFileConfigFileContent(S,{useCaseSensitiveFileNames:!0,readDirectory:()=>[],fileExists:(f)=>g(f)!==void 0||m(f)!==void 0,readFile:(f)=>g(f)??m(f)},i);if(O.errors.length>0){let f=O.errors.filter((z)=>z.category===l.DiagnosticCategory.Error&&z.code!==18003);if(f.length>0){let z=f.map((V)=>l.flattenDiagnosticMessageText(V.messageText,`
|
|
7
7
|
`)).join("; ");return gu(p("semantic",`tsconfig compile error: ${z}`))}}let _=new su(O.fileNames,O.options,i,m),A=l.createLanguageService(_);return new In(A,_)}get isDisposed(){return this.#g}getProgram(){this.#i();let n=this.#n.getProgram();if(!n)throw Error("TscProgram: LanguageService returned null Program");return n}getChecker(){return this.#i(),this.getProgram().getTypeChecker()}getLanguageService(){return this.#i(),this.#n}notifyFileChanged(n,u){if(this.#g)return;this.#u.updateFile(n,u)}removeFile(n){if(this.#g)return;this.#u.removeFile(n)}dispose(){if(this.#g)return;this.#g=!0,this.#n.dispose()}#i(){if(this.#g)throw Error("TscProgram is disposed")}}class su{#n;#u;#g;#i;#m=new Map;constructor(n,u,g,m){this.#n=[...n],this.#u=u,this.#g=g,this.#i=m}updateFile(n,u){let g=this.#m.get(n);if(g)g.version+=1,g.content=u;else this.#m.set(n,{version:1,content:u})}removeFile(n){this.#m.delete(n),this.#n=this.#n.filter((u)=>u!==n)}getScriptFileNames(){let n=[...this.#m.keys()];return[...this.#n.filter((g)=>!this.#m.has(g)),...n]}getScriptVersion(n){let u=this.#m.get(n);return u?String(u.version):"0"}getScriptSnapshot(n){let u=this.#m.get(n);if(u)return l.ScriptSnapshot.fromString(u.content);let g=this.#i(n);if(g!==void 0)return l.ScriptSnapshot.fromString(g);return}getCurrentDirectory(){return this.#g}getCompilationSettings(){return this.#u}getDefaultLibFileName(n){return l.getDefaultLibFilePath(n)}fileExists(n){if(this.#m.has(n))return!0;return this.#i(n)!==void 0}readFile(n){let u=this.#m.get(n);if(u)return u.content;return this.#i(n)}}import q from"typescript";import Wm from"typescript";function c(n,u){if(u<0||u>=n.getEnd())return;function g(m){let i=m.getStart(n,!1),t=m.getEnd();if(u<i||u>=t)return;let S;return Wm.forEachChild(m,(w)=>{if(!S)S=g(w)}),S??m}return g(n)}function Hm(n){return!!(n.flags&q.TypeFlags.Object)&&!!(n.objectFlags&q.ObjectFlags.Reference)}function Dn(n,u,g=0){let m=n.typeToString(u),i=u.flags,t=!!(i&q.TypeFlags.Union),S=!!(i&q.TypeFlags.Intersection),w;if(g<8&&Hm(u)){let f=n.getTypeArguments(u);if(f.length>0)w=f}let O=!!(i&q.TypeFlags.TypeParameter)||w!==void 0&&w.length>0,_;if(t&&g<8)_=u.types.map((f)=>Dn(n,f,g+1));else if(S&&g<8)_=u.types.map((f)=>Dn(n,f,g+1));let A;if(w&&w.length>0)A=w.map((f)=>Dn(n,f,g+1));return{text:m,flags:i,isUnion:t,isIntersection:S,isGeneric:O,members:_,typeArguments:A}}function Qm(n){return q.isFunctionDeclaration(n)||q.isVariableDeclaration(n)||q.isClassDeclaration(n)||q.isInterfaceDeclaration(n)||q.isTypeAliasDeclaration(n)||q.isEnumDeclaration(n)||q.isMethodDeclaration(n)||q.isPropertyDeclaration(n)||q.isPropertySignature(n)||q.isMethodSignature(n)}class mu{program;constructor(n){this.program=n}collectAt(n,u){let g=this.program.getProgram(),m=this.program.getChecker();if(u<0)return null;let i=g.getSourceFile(n);if(!i)return null;if(u>=i.getEnd())return null;let t=c(i,u);if(!t)return null;if(!q.isIdentifier(t))return null;try{let S=m.getTypeAtLocation(t);return Dn(m,S)}catch{return null}}collectFile(n){let u=new Map,g=this.program.getProgram(),m=this.program.getChecker(),i=g.getSourceFile(n);if(!i)return u;function t(S){if(Qm(S)&&S.name&&q.isIdentifier(S.name)){let w=S.name;try{let O=m.getTypeAtLocation(w),_=w.getStart(i);u.set(_,Dn(m,O))}catch{}}q.forEachChild(S,t)}return t(i),u}}import tn from"typescript";var Um=1000,Bm=1;function Ym(n){let u=n.declarations?.[0],g=u?.getSourceFile(),m=u?tn.getNameOfDeclaration(u):void 0;return{name:n.getName(),filePath:g?.fileName??"",position:m?.getStart(g,!1)??u?.getStart(g,!1)??0}}function kn(n,u=0){let g=n.declarations?.[0],m=g?.getSourceFile(),i=g?tn.getNameOfDeclaration(g):void 0,t=m?.fileName??"",S=i?.getStart(m,!1)??g?.getStart(m,!1)??0,w={name:n.getName(),filePath:t,position:S},O=n;if(O.parent)w.parent=Ym(O.parent);if(u<Bm){let _=n.flags,A=!!(_&tn.SymbolFlags.Enum),f=!!(_&(tn.SymbolFlags.NamespaceModule|tn.SymbolFlags.ValueModule)),z=!!(_&(tn.SymbolFlags.Class|tn.SymbolFlags.Interface));if(A&&n.exports&&n.exports.size>0){let V=[];n.exports.forEach((Q)=>{V.push(kn(Q,u+1))}),w.members=V}else if(z&&n.members&&n.members.size>0){let V=[];n.members.forEach((Q)=>{V.push(kn(Q,u+1))}),w.members=V}if(f&&n.exports&&n.exports.size>0){let V=[];n.exports.forEach((Q)=>{V.push(kn(Q,u+1))}),w.exports=V}}return w}class iu{#n;#u;#g=new Map;constructor(n,u=Um){this.#n=n,this.#u=new zn(u)}get(n,u){if(this.#n.isDisposed)return null;let g=`${n}:${u}`,m=this.#u.get(g);if(m!==void 0)return m;let t=this.#n.getProgram().getSourceFile(n);if(!t)return null;let S=c(t,u);if(!S||!tn.isIdentifier(S))return null;let O=this.#n.getChecker().getSymbolAtLocation(S);if(!O)return null;let _=kn(O);this.#u.set(g,_);let A=this.#g.get(n);if(!A)A=new Set,this.#g.set(n,A);return A.add(g),_}invalidate(n){let u=this.#g.get(n);if(u){for(let g of u)this.#u.delete(g);this.#g.delete(n)}}clear(){this.#u.clear(),this.#g.clear()}}import Zm from"typescript";class tu{#n;constructor(n){this.#n=n}findAt(n,u){if(this.#n.isDisposed)return[];let g=this.#n.getProgram(),m=g.getSourceFile(n);if(!m)return[];let i=c(m,u);if(!i||!Zm.isIdentifier(i))return[];let S=this.#n.getLanguageService().findReferences(n,u);if(!S||S.length===0)return[];let w=[];for(let O of S)for(let _ of O.references){let A=g.getSourceFile(_.fileName);if(!A)continue;let{line:f,character:z}=A.getLineAndCharacterOfPosition(_.textSpan.start);w.push({filePath:_.fileName,position:_.textSpan.start,line:f+1,column:z,isDefinition:_.isDefinition??!1,isWrite:_.isWriteAccess??!1})}return w}}import T from"typescript";function Lm(n,u){let g=c(n,u);if(!g)return;if(Ru(g))return g;let m=g.parent;for(let i=0;i<5&&m;i++){if(Ru(m))return m;m=m.parent}return g}function Ru(n){return T.isClassDeclaration(n)||T.isClassExpression(n)||T.isFunctionDeclaration(n)||T.isFunctionExpression(n)||T.isArrowFunction(n)||T.isVariableDeclaration(n)||T.isObjectLiteralExpression(n)}function Fu(n){if(T.isClassDeclaration(n)||T.isClassExpression(n))return"class";if(T.isFunctionDeclaration(n)||T.isFunctionExpression(n)||T.isArrowFunction(n))return"function";if(T.isObjectLiteralExpression(n))return"object";if(T.isVariableDeclaration(n)&&n.initializer)return Fu(n.initializer);return"class"}function Xm(n,u){if(T.isClassDeclaration(n)||T.isFunctionDeclaration(n))return n.name?.getText(u)??"";if(T.isClassExpression(n))return n.name?.getText(u)??"";if(T.isVariableDeclaration(n)&&T.isIdentifier(n.name))return n.name.getText(u);if(T.isFunctionExpression(n))return n.name?.getText(u)??"";if(T.isArrowFunction(n)&&n.parent&&T.isVariableDeclaration(n.parent)){if(T.isIdentifier(n.parent.name))return n.parent.name.getText(u)}if(T.isObjectLiteralExpression(n)&&n.parent&&T.isVariableDeclaration(n.parent)){if(T.isIdentifier(n.parent.name))return n.parent.name.getText(u)}return""}function Im(n){if(!T.isClassDeclaration(n)&&!T.isClassExpression(n))return!1;let u=n.heritageClauses;if(!u)return!1;return u.some((g)=>g.token===T.SyntaxKind.ImplementsKeyword)}class wu{#n;constructor(n){this.#n=n}findAt(n,u){if(this.#n.isDisposed)return[];let g=this.#n.getProgram(),m=g.getSourceFile(n);if(!m)return[];let i=c(m,u);if(!i||!T.isIdentifier(i))return[];let S=this.#n.getLanguageService().getImplementationAtPosition(n,u);if(!S||S.length===0)return[];let w=[];for(let O of S){if(O.kind===T.ScriptElementKind.interfaceElement||O.kind===T.ScriptElementKind.typeElement)continue;let _=g.getSourceFile(O.fileName);if(!_)continue;let A=Lm(_,O.textSpan.start);if(!A)continue;let f=Fu(A),z=Xm(A,_),V=Im(A);w.push({filePath:O.fileName,symbolName:z,position:O.textSpan.start,kind:f,isExplicit:V})}return w}}function au(n){return b.canHaveModifiers(n)&&b.getModifiers(n)?.some((u)=>u.kind===b.SyntaxKind.ExportKeyword)===!0}function Cm(n){if(b.isFunctionDeclaration(n))return"function";if(b.isClassDeclaration(n))return"class";if(b.isInterfaceDeclaration(n))return"interface";if(b.isTypeAliasDeclaration(n))return"type";if(b.isEnumDeclaration(n))return"enum";if(b.isVariableDeclaration(n))return"const";if(b.isVariableStatement(n))return"const";return"unknown"}function bu(n){if(n>=97&&n<=122)return!0;if(n>=65&&n<=90)return!0;if(n>=48&&n<=57)return!0;if(n===95||n===36)return!0;return!1}class Cn{#n;#u;#g;#i;#m;#t=!1;constructor(n,u,g,m,i){this.#n=n,this.#u=u,this.#g=g,this.#i=m,this.#m=i}static create(n,u={}){let g=In.create(n,{readConfigFile:u.readConfigFile,resolveNonTrackedFile:u.resolveNonTrackedFile});if(km(g))return g;let m=g,i=u.typeCollector??new mu(m),t=u.symbolGraph??new iu(m),S=u.referenceResolver??new tu(m),w=u.implementationFinder??new wu(m);return new Cn(m,i,t,S,w)}get isDisposed(){return this.#t}collectTypeAt(n,u){return this.#w(),this.#u.collectAt(n,u)}collectFileTypes(n){return this.#w(),this.#u.collectFile(n)}findReferences(n,u){return this.#w(),this.#i.findAt(n,u)}findImplementations(n,u){return this.#w(),this.#m.findAt(n,u)}getSymbolNode(n,u){return this.#w(),this.#g.get(n,u)}getModuleInterface(n){this.#w();let u=this.#u.collectFile(n),g=[],i=this.#n.getProgram().getSourceFile(n);if(!i)return{filePath:n,exports:g};function t(S){if(b.isVariableStatement(S)&&au(S)){for(let w of S.declarationList.declarations)if(b.isIdentifier(w.name)){let O=w.name.getStart(i),_=u.get(O)??null;g.push({name:w.name.text,kind:"const",resolvedType:_})}return}if((b.isFunctionDeclaration(S)||b.isClassDeclaration(S)||b.isInterfaceDeclaration(S)||b.isTypeAliasDeclaration(S)||b.isEnumDeclaration(S))&&au(S)&&S.name){let w=S.name,O=w.getStart(i),_=u.get(O)??null;g.push({name:w.text,kind:Cm(S),resolvedType:_});return}b.forEachChild(S,t)}return t(i),{filePath:n,exports:g}}notifyFileChanged(n,u){if(this.#t)return;this.#n.notifyFileChanged(n,u),this.#g.invalidate(n)}notifyFileDeleted(n){if(this.#t)return;this.#n.removeFile(n),this.#g.invalidate(n)}lineColumnToPosition(n,u,g){this.#w();let m=this.#n.getProgram().getSourceFile(n);if(!m)return null;try{return b.getPositionOfLineAndCharacter(m,u-1,g)}catch{return null}}findNamePosition(n,u,g){this.#w();let m=this.#n.getProgram().getSourceFile(n);if(!m)return null;let i=m.getFullText(),t=u;while(t<i.length){let S=i.indexOf(g,t);if(S<0)return null;let w=S>0?i.charCodeAt(S-1):32,O=S+g.length<i.length?i.charCodeAt(S+g.length):32;if(!bu(w)&&!bu(O))return S;t=S+1}return null}dispose(){if(this.#t)return;this.#t=!0,this.#n.dispose(),this.#g.clear()}#w(){if(this.#t)throw Error("SemanticLayer is disposed")}}class Tn{options;adjacencyList=new Map;reverseAdjacencyList=new Map;constructor(n){this.options=n}build(){this.adjacencyList=new Map,this.reverseAdjacencyList=new Map;let u=[this.options.project,...this.options.additionalProjects??[]].flatMap((g)=>[...this.options.relationRepo.getByType(g,"imports"),...this.options.relationRepo.getByType(g,"type-references"),...this.options.relationRepo.getByType(g,"re-exports")]);for(let g of u){let{srcFilePath:m,dstFilePath:i}=g;if(!this.adjacencyList.has(m))this.adjacencyList.set(m,new Set);if(this.adjacencyList.get(m).add(i),!this.adjacencyList.has(i))this.adjacencyList.set(i,new Set);if(!this.reverseAdjacencyList.has(i))this.reverseAdjacencyList.set(i,new Set);this.reverseAdjacencyList.get(i).add(m)}}patchFiles(n,u,g){let m=new Set([...n,...u]);for(let i of m){let t=this.adjacencyList.get(i);if(t){for(let w of t)this.reverseAdjacencyList.get(w)?.delete(i);t.clear()}let S=this.reverseAdjacencyList.get(i);if(S){for(let w of S)this.adjacencyList.get(w)?.delete(i);S.clear()}}for(let i of u)this.adjacencyList.delete(i),this.reverseAdjacencyList.delete(i);for(let i of n){let t=g(i);for(let S of t){if(!this.adjacencyList.has(S.srcFilePath))this.adjacencyList.set(S.srcFilePath,new Set);if(this.adjacencyList.get(S.srcFilePath).add(S.dstFilePath),!this.adjacencyList.has(S.dstFilePath))this.adjacencyList.set(S.dstFilePath,new Set);if(!this.reverseAdjacencyList.has(S.dstFilePath))this.reverseAdjacencyList.set(S.dstFilePath,new Set);this.reverseAdjacencyList.get(S.dstFilePath).add(S.srcFilePath)}}}getDependencies(n){return Array.from(this.adjacencyList.get(n)??[])}getDependents(n){return Array.from(this.reverseAdjacencyList.get(n)??[])}getTransitiveDependents(n){let u=new Set,g=[n];while(g.length>0){let m=g.shift();for(let i of this.reverseAdjacencyList.get(m)??[])if(!u.has(i))u.add(i),g.push(i)}return Array.from(u)}hasCycle(){let n=new Set,u=new Set;for(let g of this.adjacencyList.keys()){if(n.has(g))continue;let m=[{node:g,entered:!1}];while(m.length>0){let i=m.pop();if(i.entered){u.delete(i.node);continue}if(u.has(i.node))return!0;if(n.has(i.node))continue;n.add(i.node),u.add(i.node),m.push({node:i.node,entered:!0});for(let t of this.adjacencyList.get(i.node)??[]){if(u.has(t))return!0;if(!n.has(t))m.push({node:t,entered:!1})}}}return!1}getAffectedByChange(n){let u=new Set;for(let g of n)for(let m of this.getTransitiveDependents(g))u.add(m);return Array.from(u)}getAdjacencyList(){let n=new Map;for(let[u,g]of this.adjacencyList)n.set(u,Array.from(g));return n}getTransitiveDependencies(n){let u=new Set,g=[n];while(g.length>0){let m=g.shift();for(let i of this.adjacencyList.get(m)??[])if(!u.has(i))u.add(i),g.push(i)}return Array.from(u)}getCyclePaths(n){let u=n?.maxCycles??1/0;if(u<=0)return[];let g=new Map;for(let[m,i]of this.adjacencyList)g.set(m,Array.from(i));return Fm(g,u)}}var Tm=(n,u)=>n.localeCompare(u);function ym(n){let u=n.length>1&&n[0]===n[n.length-1]?n.slice(0,-1):[...n];if(u.length===0)return[];let g=u;for(let m=1;m<u.length;m++){let i=u.slice(m).concat(u.slice(0,m));if(i.join("::")<g.join("::"))g=i}return[...g]}function Ou(n,u,g){let m=ym(g);if(m.length===0)return!1;let i=m.join("->");if(n.has(i))return!1;return n.add(i),u.push(m),!0}function sm(n){let u=0,g=[],m=new Set,i=new Map,t=new Map,S=[],w=(O)=>{i.set(O,u),t.set(O,u),u+=1,g.push(O),m.add(O);for(let _ of n.get(O)??[])if(!i.has(_))w(_),t.set(O,Math.min(t.get(O)??0,t.get(_)??0));else if(m.has(_))t.set(O,Math.min(t.get(O)??0,i.get(_)??0));if(t.get(O)===i.get(O)){let _=[],A="";do A=g.pop()??"",m.delete(A),_.push(A);while(A!==O&&g.length>0);S.push(_)}};for(let O of n.keys())if(!i.has(O))w(O);return{components:S}}function Rm(n,u,g){let m=[],i=new Set,t=[...n].sort(Tm),S=(w,O,_)=>{O.delete(w);let A=_.get(w);if(!A)return;for(let f of A)if(O.has(f))S(f,O,_);A.clear()};for(let w=0;w<t.length&&m.length<g;w++){let O=t[w]??"",_=new Set(t.slice(w)),A=new Set,f=new Map,z=[],V=(B)=>(u.get(B)??[]).filter((Y)=>_.has(Y)),Q=(B)=>{if(m.length>=g)return!0;let Y=!1;z.push(B),A.add(B);for(let N of V(B)){if(m.length>=g)break;if(N===O)Ou(i,m,z.concat(O)),Y=!0;else if(!A.has(N)){if(Q(N))Y=!0}}if(Y)S(B,A,f);else for(let N of V(B)){let $=f.get(N)??new Set;$.add(B),f.set(N,$)}return z.pop(),Y};Q(O)}return m}function Fm(n,u){let{components:g}=sm(n),m=[],i=new Set;for(let t of g){if(m.length>=u)break;if(t.length===0)continue;if(t.length===1){let O=t[0]??"";if((n.get(O)??[]).includes(O))Ou(i,m,[O,O]);continue}let S=u-m.length,w=Rm(t,n,S);for(let O of w){if(m.length>=u)break;Ou(i,m,O)}}return m}var am=15000;function yn(n){n.graphCache=null,n.graphCacheKey=null,n.graphCacheBuiltAt=null}function An(n,u){let g=u??"__cross__";if(n.graphCache&&n.graphCacheBuiltAt!==null){if(Date.now()-n.graphCacheBuiltAt>am)n.graphCache=null,n.graphCacheKey=null,n.graphCacheBuiltAt=null}if(n.graphCache&&n.graphCacheKey===g)return n.graphCache;let m=new Tn({relationRepo:n.relationRepo,project:u??n.defaultProject,additionalProjects:u?void 0:n.boundaries?.map((i)=>i.project)});return m.build(),n.graphCache=m,n.graphCacheKey=g,n.graphCacheBuiltAt=Date.now(),m}function qu(n,u,g,m=1e4){if(n.closed)throw new J("closed","Gildash: instance is closed");try{return n.relationSearchFn({relationRepo:n.relationRepo,project:g??n.defaultProject,query:{srcFilePath:u,type:"imports",project:g??n.defaultProject,limit:m}}).map((i)=>i.dstFilePath)}catch(i){if(i instanceof J)throw i;throw new J("search","Gildash: getDependencies failed",{cause:i})}}function pu(n,u,g,m=1e4){if(n.closed)throw new J("closed","Gildash: instance is closed");try{return n.relationSearchFn({relationRepo:n.relationRepo,project:g??n.defaultProject,query:{dstFilePath:u,type:"imports",project:g??n.defaultProject,limit:m}}).map((i)=>i.srcFilePath)}catch(i){if(i instanceof J)throw i;throw new J("search","Gildash: getDependents failed",{cause:i})}}async function vu(n,u,g){if(n.closed)throw new J("closed","Gildash: instance is closed");try{return An(n,g).getAffectedByChange(u)}catch(m){if(m instanceof J)throw m;throw new J("search","Gildash: getAffected failed",{cause:m})}}async function Gu(n,u){if(n.closed)throw new J("closed","Gildash: instance is closed");try{return An(n,u).hasCycle()}catch(g){if(g instanceof J)throw g;throw new J("search","Gildash: hasCycle failed",{cause:g})}}async function Eu(n,u){if(n.closed)throw new J("closed","Gildash: instance is closed");try{return An(n,u).getAdjacencyList()}catch(g){if(g instanceof J)throw g;throw new J("search","Gildash: getImportGraph failed",{cause:g})}}async function ju(n,u,g){if(n.closed)throw new J("closed","Gildash: instance is closed");try{return An(n,g).getTransitiveDependencies(u)}catch(m){if(m instanceof J)throw m;throw new J("search","Gildash: getTransitiveDependencies failed",{cause:m})}}async function Pu(n,u,g){if(n.closed)throw new J("closed","Gildash: instance is closed");try{return An(n,u).getCyclePaths(g)}catch(m){if(m instanceof J)throw m;throw new J("search","Gildash: getCyclePaths failed",{cause:m})}}async function hu(n,u,g){if(n.closed)throw new J("closed","Gildash: instance is closed");try{let m=An(n,g);return{filePath:u,fanIn:m.getDependents(u).length,fanOut:m.getDependencies(u).length}}catch(m){if(m instanceof J)throw m;throw new J("search","Gildash: getFanMetrics failed",{cause:m})}}var pm=30000,du=15000,vm=10;function Gm(n,u){return(g)=>{for(let m of n.onFileChangedCallbacks)try{m(g)}catch(i){n.logger.error("[Gildash] onFileChanged callback threw:",i)}if(u.handleWatcherEvent?.(g),n.semanticLayer)if(g.eventType==="delete")try{n.semanticLayer.notifyFileDeleted(g.filePath)}catch(m){n.logger.error("[Gildash] semanticLayer.notifyFileDeleted threw:",m);for(let i of n.onErrorCallbacks)try{i(m instanceof J?m:new J("semantic","semantic notifyFileDeleted failed",{cause:m}))}catch{}}else n.readFileFn(g.filePath).then((m)=>{try{n.semanticLayer?.notifyFileChanged(g.filePath,m)}catch(i){n.logger.error("[Gildash] semanticLayer.notifyFileChanged threw:",i);for(let t of n.onErrorCallbacks)try{t(i instanceof J?i:new J("semantic","semantic notifyFileChanged failed",{cause:i}))}catch{}}}).catch((m)=>{n.logger.error("[Gildash] failed to read file for semantic layer",g.filePath,m);try{n.semanticLayer?.notifyFileDeleted(g.filePath)}catch(i){n.logger.error("[Gildash] semanticLayer.notifyFileDeleted threw during read error recovery:",i)}})}}async function Em(n){if(!n.semanticLayer)return;let u=n.fileRepo.getAllFiles(n.defaultProject);await Promise.all(u.map(async(g)=>{try{let m=Vn.resolve(n.projectRoot,g.filePath),i=await n.readFileFn(m);n.semanticLayer?.notifyFileChanged(m,i)}catch{}}))}async function xu(n,u){let g=n.coordinatorFactory?n.coordinatorFactory():new ln({projectRoot:n.projectRoot,boundaries:n.boundaries,extensions:n.extensions,ignorePatterns:n.ignorePatterns,dbConnection:n.db,parseCache:n.parseCache,fileRepo:n.fileRepo,symbolRepo:n.symbolRepo,relationRepo:n.relationRepo,logger:n.logger});n.coordinator=g;for(let m of n.onIndexedCallbacks)g.onIndexed(m);if(g.onIndexed((m)=>{let i=m.changedFiles.length+m.deletedFiles.length;if(n.graphCache&&i>0&&i<100){let t=n.relationRepo;n.graphCache.patchFiles(m.changedFiles,m.deletedFiles,(S)=>{return[n.defaultProject,...n.boundaries.map((O)=>O.project)].flatMap((O)=>t.getByType(O,"imports").concat(t.getByType(O,"type-references")).concat(t.getByType(O,"re-exports"))).filter((O)=>O.srcFilePath===S||O.dstFilePath===S).map((O)=>({srcFilePath:O.srcFilePath,dstFilePath:O.dstFilePath}))}),n.graphCacheBuiltAt=Date.now()}else yn(n)}),u.isWatchMode){let m=n.watcherFactory?n.watcherFactory():new En({projectRoot:n.projectRoot,ignorePatterns:n.ignorePatterns,extensions:n.extensions},void 0,n.logger);await m.start(Gm(n,g)).then((i)=>{if(Kn(i))throw i.data}),n.watcher=m,n.timer=setInterval(()=>{n.updateHeartbeatFn(n.db,process.pid)},pm)}await g.fullIndex(),await Em(n)}function jm(n,u){let g=["SIGTERM","SIGINT","beforeExit"];for(let m of g){let i=()=>{u().catch((t)=>n.logger.error("[Gildash] close error during signal",m,t))};if(m==="beforeExit")process.on("beforeExit",i);else process.on(m,i);n.signalHandlers.push([m,i])}}async function ou(n){let{projectRoot:u,extensions:g=[".ts",".mts",".cts"],ignorePatterns:m=["**/node_modules/**"],parseCacheCapacity:i=500,logger:t=console,existsSyncFn:S=qm,dbConnectionFactory:w,watcherFactory:O,coordinatorFactory:_,repositoryFactory:A,acquireWatcherRoleFn:f=Cu,releaseWatcherRoleFn:z=Tu,updateHeartbeatFn:V=yu,discoverProjectsFn:Q=Bn,parseSourceFn:B=$n,extractSymbolsFn:Y=Ln,extractRelationsFn:N=Xn,symbolSearchFn:$=en,relationSearchFn:r=nu,patternSearchFn:M=uu,loadTsconfigPathsFn:D=Mn,readFileFn:H=async(X)=>Bun.file(X).text(),unlinkFn:Z=async(X)=>{await Bun.file(X).unlink()},watchMode:L,semantic:C,semanticLayerFactory:U}=n;if(!Vn.isAbsolute(u))throw new J("validation",`Gildash: projectRoot must be an absolute path, got: "${u}"`);if(!S(u))throw new J("validation",`Gildash: projectRoot does not exist: "${u}"`);let W=w?w():new bn({projectRoot:u}),R=W.open();if(Kn(R))throw R.data;try{let X=await Q(u),v=X[0]?.project??Vn.basename(u),E=A?A():(()=>{let h=W;return{fileRepo:new qn(h),symbolRepo:new pn(h),relationRepo:new vn(h),parseCache:new cn(i)}})(),P=L??!0,Rn=crypto.randomUUID(),e;if(P)e=await Promise.resolve(f(W,process.pid,{instanceId:Rn}));else e="owner";let I={projectRoot:u,extensions:g,ignorePatterns:m,logger:t,defaultProject:v,role:e,db:W,symbolRepo:E.symbolRepo,relationRepo:E.relationRepo,fileRepo:E.fileRepo,parseCache:E.parseCache,releaseWatcherRoleFn:z,parseSourceFn:B,extractSymbolsFn:Y,extractRelationsFn:N,symbolSearchFn:$,relationSearchFn:r,patternSearchFn:M,readFileFn:H,unlinkFn:Z,existsSyncFn:S,acquireWatcherRoleFn:f,updateHeartbeatFn:V,watcherFactory:O,coordinatorFactory:_,instanceId:Rn,closed:!1,coordinator:null,watcher:null,timer:null,signalHandlers:[],tsconfigPaths:null,boundaries:X,onIndexedCallbacks:new Set,onFileChangedCallbacks:new Set,onErrorCallbacks:new Set,onRoleChangedCallbacks:new Set,graphCache:null,graphCacheKey:null,graphCacheBuiltAt:null,semanticLayer:null};if(Yn(u),I.tsconfigPaths=await D(u),C){let h=Vn.join(u,"tsconfig.json");try{if(U)I.semanticLayer=U(h);else{let d=Cn.create(h);if(Kn(d))throw d.data;I.semanticLayer=d}}catch(d){if(d instanceof J)throw d;throw new J("semantic","Gildash: semantic layer creation failed",{cause:d})}}if(e==="owner")await xu(I,{isWatchMode:P});else{let h=0,d=async()=>{try{let rn=await Promise.resolve(I.acquireWatcherRoleFn(I.db,process.pid,{instanceId:I.instanceId}));if(h=0,rn==="owner"){for(let fn of I.onRoleChangedCallbacks)try{fn("owner")}catch(x){I.logger.error("[Gildash] onRoleChanged callback threw:",x)}clearInterval(I.timer),I.timer=null;try{await xu(I,{isWatchMode:!0})}catch(fn){if(I.logger.error("[Gildash] owner promotion failed, reverting to reader",fn),I.watcher){let x=await I.watcher.close();if(Kn(x))I.logger.error("[Gildash] watcher close error during promotion rollback",x.data);I.watcher=null}if(I.coordinator)await I.coordinator.shutdown().catch((x)=>I.logger.error("[Gildash] coordinator shutdown error during promotion rollback",x)),I.coordinator=null;if(I.timer===null)I.timer=setInterval(d,du)}}}catch(rn){h++;let fn=rn instanceof J?rn:new J("watcher","Gildash: healthcheck error",{cause:rn});for(let x of I.onErrorCallbacks)try{x(fn)}catch(Xg){I.logger.error("[Gildash] onError callback threw:",Xg)}if(I.logger.error("[Gildash] healthcheck error",rn),h>=vm)I.logger.error("[Gildash] healthcheck failed too many times, shutting down"),clearInterval(I.timer),I.timer=null,sn(I).catch((x)=>I.logger.error("[Gildash] close error during healthcheck shutdown",x))}};I.timer=setInterval(d,du)}if(P)jm(I,()=>sn(I));return I}catch(X){if(W.close(),X instanceof J)throw X;throw new J("store","Gildash: initialization failed",{cause:X})}}async function sn(n,u){if(n.closed)return;n.closed=!0;let g=[];for(let[m,i]of n.signalHandlers)if(m==="beforeExit")process.off("beforeExit",i);else process.off(m,i);if(n.signalHandlers=[],n.semanticLayer){try{n.semanticLayer.dispose()}catch(m){g.push(m instanceof Error?m:Error(String(m)))}n.semanticLayer=null}if(n.coordinator)try{await n.coordinator.shutdown()}catch(m){g.push(m instanceof Error?m:Error(String(m)))}if(n.watcher){let m=await n.watcher.close();if(Kn(m))g.push(m.data)}if(n.timer!==null)clearInterval(n.timer),n.timer=null;try{n.releaseWatcherRoleFn(n.db,process.pid)}catch(m){g.push(m instanceof Error?m:Error(String(m)))}try{n.db.close()}catch(m){g.push(m instanceof Error?m:Error(String(m)))}if(u?.cleanup)for(let m of["","-wal","-shm"])try{await n.unlinkFn(Vn.join(n.projectRoot,nn,Wn+m))}catch{}if(g.length>0)throw new J("close","Gildash: one or more errors occurred during close()",{cause:g})}import{isErr as lu}from"@zipbul/result";function cu(n,u,g,m){if(n.closed)throw new J("closed","Gildash: instance is closed");let i=n.parseSourceFn(u,g,m);if(lu(i))throw i.data;return n.parseCache.set(u,i),i}async function eu(n,u,g){if(n.closed)throw new J("closed","Gildash: instance is closed");let m=new Map,i=[];return await Promise.all(u.map(async(t)=>{try{let S=await n.readFileFn(t),w=n.parseSourceFn(t,S,g);if(!lu(w))m.set(t,w);else i.push({filePath:t,error:w.data})}catch(S){i.push({filePath:t,error:S instanceof Error?S:Error(String(S))})}})),{parsed:m,failures:i}}function ng(n,u){if(n.closed)return;return n.parseCache.get(u)}function ug(n,u){if(n.closed)throw new J("closed","Gildash: instance is closed");return n.extractSymbolsFn(u)}function gg(n,u){if(n.closed)throw new J("closed","Gildash: instance is closed");return n.extractRelationsFn(u.program,u.filePath,n.tsconfigPaths??void 0)}import mg from"path";function ig(n,u){if(n.closed)throw new J("closed","Gildash: instance is closed");try{return n.symbolRepo.getStats(u??n.defaultProject)}catch(g){if(g instanceof J)throw g;throw new J("store","Gildash: getStats failed",{cause:g})}}function Su(n,u){if(n.closed)throw new J("closed","Gildash: instance is closed");try{return n.symbolSearchFn({symbolRepo:n.symbolRepo,project:n.defaultProject,query:u})}catch(g){if(g instanceof J)throw g;throw new J("search","Gildash: searchSymbols failed",{cause:g})}}function tg(n,u){if(n.closed)throw new J("closed","Gildash: instance is closed");try{return n.relationSearchFn({relationRepo:n.relationRepo,project:n.defaultProject,query:u})}catch(g){if(g instanceof J)throw g;throw new J("search","Gildash: searchRelations failed",{cause:g})}}function wg(n,u){if(n.closed)throw new J("closed","Gildash: instance is closed");try{return n.symbolSearchFn({symbolRepo:n.symbolRepo,project:void 0,query:u})}catch(g){if(g instanceof J)throw g;throw new J("search","Gildash: searchAllSymbols failed",{cause:g})}}function Og(n,u){if(n.closed)throw new J("closed","Gildash: instance is closed");try{return n.relationSearchFn({relationRepo:n.relationRepo,project:void 0,query:u})}catch(g){if(g instanceof J)throw g;throw new J("search","Gildash: searchAllRelations failed",{cause:g})}}function Sg(n,u){if(n.closed)throw new J("closed","Gildash: instance is closed");try{return n.fileRepo.getAllFiles(u??n.defaultProject)}catch(g){if(g instanceof J)throw g;throw new J("store","Gildash: listIndexedFiles failed",{cause:g})}}function rg(n,u,g){if(n.closed)throw new J("closed","Gildash: instance is closed");try{return n.relationSearchFn({relationRepo:n.relationRepo,project:g??n.defaultProject,query:{srcFilePath:u,dstFilePath:u,limit:1e4}})}catch(m){if(m instanceof J)throw m;throw new J("search","Gildash: getInternalRelations failed",{cause:m})}}function _g(n,u,g,m){if(n.closed)throw new J("closed","Gildash: instance is closed");try{let i=m??n.defaultProject,t=n.symbolSearchFn({symbolRepo:n.symbolRepo,project:i,query:{text:u,exact:!0,filePath:g,limit:1}});if(t.length===0)return null;let S=t[0],w=S.detail,O={...S,members:Array.isArray(w.members)?w.members:void 0,jsDoc:typeof w.jsDoc==="string"?w.jsDoc:void 0,parameters:typeof w.parameters==="string"?w.parameters:void 0,returnType:typeof w.returnType==="string"?w.returnType:void 0,heritage:Array.isArray(w.heritage)?w.heritage:void 0,decorators:Array.isArray(w.decorators)?w.decorators:void 0,typeParameters:typeof w.typeParameters==="string"?w.typeParameters:void 0};if(n.semanticLayer)try{let _=mg.isAbsolute(g)?g:mg.resolve(n.projectRoot,g),A=n.semanticLayer.lineColumnToPosition(_,S.span.start.line,S.span.start.column);if(A!==null){let f=n.semanticLayer.findNamePosition(_,A,S.name)??A,z=n.semanticLayer.collectTypeAt(_,f);if(z)O.resolvedType=z}}catch{}return O}catch(i){if(i instanceof J)throw i;throw new J("search","Gildash: getFullSymbol failed",{cause:i})}}function Jg(n,u,g){if(n.closed)throw new J("closed","Gildash: instance is closed");try{let m=g??n.defaultProject,i=n.fileRepo.getFile(m,u);if(!i)throw new J("search",`Gildash: file '${u}' is not in the index`);let t=n.symbolRepo.getFileSymbols(m,u),S=n.relationRepo.getOutgoing(m,u);return{filePath:i.filePath,lineCount:i.lineCount??0,size:i.size,symbolCount:t.length,exportedSymbolCount:t.filter((w)=>w.isExported).length,relationCount:S.length}}catch(m){if(m instanceof J)throw m;throw new J("store","Gildash: getFileStats failed",{cause:m})}}function Ag(n,u,g){if(n.closed)throw new J("closed","Gildash: instance is closed");try{return n.fileRepo.getFile(g??n.defaultProject,u)}catch(m){if(m instanceof J)throw m;throw new J("store","Gildash: getFileInfo failed",{cause:m})}}function fg(n,u,g){return Su(n,{filePath:u,project:g??void 0,limit:1e4})}function Ng(n,u,g){if(n.closed)throw new J("closed","Gildash: instance is closed");try{let i=n.symbolSearchFn({symbolRepo:n.symbolRepo,project:g??n.defaultProject,query:{filePath:u,isExported:!0}}).map((t)=>({name:t.name,kind:t.kind,parameters:t.detail.parameters??void 0,returnType:t.detail.returnType??void 0,jsDoc:t.detail.jsDoc??void 0}));return{filePath:u,exports:i}}catch(m){if(m instanceof J)throw m;throw new J("search","Gildash: getModuleInterface failed",{cause:m})}}import Mg from"path";function ru(n,u,g,m){let i=m??n.defaultProject,t=n.symbolSearchFn({symbolRepo:n.symbolRepo,project:i,query:{text:u,exact:!0,filePath:g,limit:1}});if(t.length===0)return null;let S=t[0],w=Mg.isAbsolute(g)?g:Mg.resolve(n.projectRoot,g),O=n.semanticLayer.lineColumnToPosition(w,S.span.start.line,S.span.start.column);if(O===null)return null;let _=n.semanticLayer.findNamePosition(w,O,S.name)??O;return{sym:S,position:_,absPath:w}}function $g(n,u,g,m){if(n.closed)throw new J("closed","Gildash: instance is closed");if(!n.semanticLayer)throw new J("semantic","Gildash: semantic layer is not enabled");try{let i=ru(n,u,g,m);if(!i)return null;return n.semanticLayer.collectTypeAt(i.absPath,i.position)}catch(i){if(i instanceof J)throw i;throw new J("search","Gildash: getResolvedType failed",{cause:i})}}function zg(n,u,g,m){if(n.closed)throw new J("closed","Gildash: instance is closed");if(!n.semanticLayer)throw new J("semantic","Gildash: semantic layer is not enabled");try{let i=ru(n,u,g,m);if(!i)throw new J("search",`Gildash: symbol '${u}' not found in '${g}'`);return n.semanticLayer.findReferences(i.absPath,i.position)}catch(i){if(i instanceof J)throw i;throw new J("search","Gildash: getSemanticReferences failed",{cause:i})}}function Dg(n,u,g,m){if(n.closed)throw new J("closed","Gildash: instance is closed");if(!n.semanticLayer)throw new J("semantic","Gildash: semantic layer is not enabled");try{let i=ru(n,u,g,m);if(!i)throw new J("search",`Gildash: symbol '${u}' not found in '${g}'`);return n.semanticLayer.findImplementations(i.absPath,i.position)}catch(i){if(i instanceof J)throw i;throw new J("search","Gildash: getImplementations failed",{cause:i})}}function Kg(n,u){if(n.closed)throw new J("closed","Gildash: instance is closed");if(!n.semanticLayer)throw new J("semantic","Gildash: semantic layer is not enabled");try{return n.semanticLayer.getModuleInterface(u)}catch(g){if(g instanceof J)throw g;throw new J("search","Gildash: getSemanticModuleInterface failed",{cause:g})}}function Vg(n,u){let g=new Map(n.map((w)=>[`${w.name}::${w.filePath}`,w])),m=new Map(u.map((w)=>[`${w.name}::${w.filePath}`,w])),i=[],t=[],S=[];for(let[w,O]of m){let _=g.get(w);if(!_)i.push(O);else if(_.fingerprint!==O.fingerprint)S.push({before:_,after:O})}for(let[w,O]of g)if(!m.has(w))t.push(O);return{added:i,removed:t,modified:S}}function Wg(n,u){if(n.onIndexedCallbacks.add(u),!n.coordinator)return()=>{n.onIndexedCallbacks.delete(u)};let g=n.coordinator.onIndexed(u);return()=>{n.onIndexedCallbacks.delete(u),g()}}async function Hg(n){if(n.closed)throw new J("closed","Gildash: instance is closed");if(!n.coordinator)throw new J("closed","Gildash: reindex() is not available for readers");try{let u=await n.coordinator.fullIndex();return yn(n),u}catch(u){if(u instanceof J)throw u;throw new J("index","Gildash: reindex failed",{cause:u})}}function Qg(n,u,g,m){if(n.closed)throw new J("closed","Gildash: instance is closed");let i=m??n.defaultProject,t=new Set,S=[],w=u,O=g;for(;;){let _=`${O}::${w}`;if(t.has(_))return{originalName:w,originalFilePath:O,reExportChain:S,circular:!0};t.add(_);let A=n.relationSearchFn({relationRepo:n.relationRepo,project:i,query:{type:"re-exports",srcFilePath:O,limit:500}}),f,z;for(let V of A){let Q;if(V.metaJson)try{let Y=JSON.parse(V.metaJson);if(Array.isArray(Y.specifiers))Q=Y.specifiers}catch{}if(!Q)continue;let B=Q.find((Y)=>Y.exported===w);if(!B)continue;f=V.dstFilePath,z=B.local;break}if(!f||!z)return{originalName:w,originalFilePath:O,reExportChain:S,circular:!1};S.push({filePath:O,exportedAs:w}),O=f,w=z}}function Ug(n,u){return n.onFileChangedCallbacks.add(u),()=>{n.onFileChangedCallbacks.delete(u)}}function Bg(n,u){return n.onErrorCallbacks.add(u),()=>{n.onErrorCallbacks.delete(u)}}function Yg(n,u){return n.onRoleChangedCallbacks.add(u),()=>{n.onRoleChangedCallbacks.delete(u)}}async function Zg(n,u,g){if(n.closed)throw new J("closed","Gildash: instance is closed");try{let m=g?.project??n.defaultProject,i=g?.filePaths?g.filePaths:n.fileRepo.getAllFiles(m).map((t)=>t.filePath);return await n.patternSearchFn({pattern:u,filePaths:i})}catch(m){if(m instanceof J)throw m;throw new J("search","Gildash: findPattern failed",{cause:m})}}async function Lg(n,u,g,m){if(n.closed)throw new J("closed","Gildash: instance is closed");try{let i=m??n.defaultProject,t=new Set,S=(w,O,_)=>{let A=`${w}::${O}`;if(t.has(A))return{symbolName:w,filePath:O,kind:_,children:[]};t.add(A);let V=n.relationSearchFn({relationRepo:n.relationRepo,project:i,query:{srcFilePath:O,srcSymbolName:w,limit:1000}}).filter((Q)=>Q.type==="extends"||Q.type==="implements").filter((Q)=>Q.dstSymbolName!=null).map((Q)=>S(Q.dstSymbolName,Q.dstFilePath,Q.type));return{symbolName:w,filePath:O,kind:_,children:V}};return S(u,g)}catch(i){if(i instanceof J)throw i;throw new J("search","Gildash: getHeritageChain failed",{cause:i})}}class _u{_ctx;get projectRoot(){return this._ctx.projectRoot}get role(){return this._ctx.role}get projects(){return[...this._ctx.boundaries]}constructor(n){this._ctx=n}static async open(n){let u=await ou(n);return new _u(u)}async close(n){return sn(this._ctx,n)}parseSource(n,u,g){return cu(this._ctx,n,u,g)}async batchParse(n,u){return eu(this._ctx,n,u)}getParsedAst(n){return ng(this._ctx,n)}extractSymbols(n){return ug(this._ctx,n)}extractRelations(n){return gg(this._ctx,n)}getStats(n){return ig(this._ctx,n)}searchSymbols(n){return Su(this._ctx,n)}searchRelations(n){return tg(this._ctx,n)}searchAllSymbols(n){return wg(this._ctx,n)}searchAllRelations(n){return Og(this._ctx,n)}listIndexedFiles(n){return Sg(this._ctx,n)}getInternalRelations(n,u){return rg(this._ctx,n,u)}getFullSymbol(n,u,g){return _g(this._ctx,n,u,g)}getFileStats(n,u){return Jg(this._ctx,n,u)}getFileInfo(n,u){return Ag(this._ctx,n,u)}getSymbolsByFile(n,u){return fg(this._ctx,n,u)}getModuleInterface(n,u){return Ng(this._ctx,n,u)}getDependencies(n,u,g=1e4){return qu(this._ctx,n,u,g)}getDependents(n,u,g=1e4){return pu(this._ctx,n,u,g)}async getAffected(n,u){return vu(this._ctx,n,u)}async hasCycle(n){return Gu(this._ctx,n)}async getImportGraph(n){return Eu(this._ctx,n)}async getTransitiveDependencies(n,u){return ju(this._ctx,n,u)}async getCyclePaths(n,u){return Pu(this._ctx,n,u)}async getFanMetrics(n,u){return hu(this._ctx,n,u)}getResolvedType(n,u,g){return $g(this._ctx,n,u,g)}getSemanticReferences(n,u,g){return zg(this._ctx,n,u,g)}getImplementations(n,u,g){return Dg(this._ctx,n,u,g)}getSemanticModuleInterface(n){return Kg(this._ctx,n)}diffSymbols(n,u){return Vg(n,u)}onIndexed(n){return Wg(this._ctx,n)}async reindex(){return Hg(this._ctx)}resolveSymbol(n,u,g){return Qg(this._ctx,n,u,g)}async findPattern(n,u){return Zg(this._ctx,n,u)}async getHeritageChain(n,u,g){return Lg(this._ctx,n,u,g)}onFileChanged(n){return Ug(this._ctx,n)}onError(n){return Bg(this._ctx,n)}onRoleChanged(n){return Yg(this._ctx,n)}}export{en as symbolSearch,nu as relationSearch,uu as patternSearch,p as gildashError,J as GildashError,_u as Gildash,Tn as DependencyGraph};
|
|
8
|
-
|
|
9
|
-
//# debugId=540D489DF398012964756E2164756E21
|
|
10
|
-
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zipbul/gildash",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.2",
|
|
4
4
|
"description": "TypeScript code indexing and dependency graph engine for Bun",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"LICENSE"
|
|
33
33
|
],
|
|
34
34
|
"scripts": {
|
|
35
|
-
"build": "bun build index.ts --outdir dist --target bun --format esm --packages external --
|
|
35
|
+
"build": "bun build index.ts --outdir dist --target bun --format esm --packages external --production && tsc -p tsconfig.build.json && cp -r src/store/migrations dist/migrations",
|
|
36
36
|
"typecheck": "tsc --noEmit",
|
|
37
37
|
"test": "bun test",
|
|
38
38
|
"test:coverage": "bun test --coverage",
|
package/dist/index.js.map
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/gildash/lifecycle.ts", "../src/store/connection.ts", "../src/errors.ts", "../src/constants.ts", "../src/store/schema.ts", "../src/store/repositories/file.repository.ts", "../src/store/repositories/symbol.repository.ts", "../src/store/repositories/fts-utils.ts", "../src/store/repositories/relation.repository.ts", "../src/watcher/project-watcher.ts", "../src/common/project-discovery.ts", "../src/common/tsconfig-resolver.ts", "../src/common/path-utils.ts", "../src/common/hasher.ts", "../src/indexer/index-coordinator.ts", "../src/parser/parse-source.ts", "../src/indexer/file-indexer.ts", "../src/parser/source-position.ts", "../src/parser/jsdoc-parser.ts", "../src/extractor/symbol-extractor.ts", "../src/indexer/symbol-indexer.ts", "../src/extractor/extractor-utils.ts", "../src/parser/ast-utils.ts", "../src/extractor/imports-extractor.ts", "../src/extractor/calls-extractor.ts", "../src/extractor/heritage-extractor.ts", "../src/extractor/relation-extractor.ts", "../src/indexer/relation-indexer.ts", "../src/watcher/ownership.ts", "../src/common/lru-cache.ts", "../src/parser/parse-cache.ts", "../src/search/symbol-search.ts", "../src/search/relation-search.ts", "../src/search/pattern-search.ts", "../src/semantic/index.ts", "../src/semantic/tsc-program.ts", "../src/semantic/type-collector.ts", "../src/semantic/ast-node-utils.ts", "../src/semantic/symbol-graph.ts", "../src/semantic/reference-resolver.ts", "../src/semantic/implementation-finder.ts", "../src/search/dependency-graph.ts", "../src/gildash/graph-api.ts", "../src/gildash/parse-api.ts", "../src/gildash/extract-api.ts", "../src/gildash/query-api.ts", "../src/gildash/semantic-api.ts", "../src/gildash/misc-api.ts", "../src/gildash/index.ts"],
|
|
4
|
-
"sourcesContent": [
|
|
5
|
-
"import { isErr } from '@zipbul/result';\nimport path from 'node:path';\nimport { existsSync } from 'node:fs';\nimport { DbConnection } from '../store/connection';\nimport { FileRepository } from '../store/repositories/file.repository';\nimport { SymbolRepository } from '../store/repositories/symbol.repository';\nimport { RelationRepository } from '../store/repositories/relation.repository';\nimport { ProjectWatcher } from '../watcher/project-watcher';\nimport { IndexCoordinator } from '../indexer/index-coordinator';\nimport type { IndexResult } from '../indexer/index-coordinator';\nimport type { FileChangeEvent } from '../watcher/types';\nimport { acquireWatcherRole, releaseWatcherRole, updateHeartbeat } from '../watcher/ownership';\nimport type { WatcherOwnerStore } from '../watcher/ownership';\nimport { discoverProjects } from '../common/project-discovery';\nimport type { TsconfigPaths } from '../common/tsconfig-resolver';\nimport { loadTsconfigPaths, clearTsconfigPathsCache } from '../common/tsconfig-resolver';\nimport { ParseCache } from '../parser/parse-cache';\nimport { parseSource as defaultParseSource } from '../parser/parse-source';\nimport { extractSymbols as defaultExtractSymbols } from '../extractor/symbol-extractor';\nimport { extractRelations as defaultExtractRelations } from '../extractor/relation-extractor';\nimport { symbolSearch as defaultSymbolSearch } from '../search/symbol-search';\nimport { relationSearch as defaultRelationSearch } from '../search/relation-search';\nimport { patternSearch as defaultPatternSearch } from '../search/pattern-search';\nimport type { PatternMatch } from '../search/pattern-search';\nimport { SemanticLayer } from '../semantic/index';\nimport { GildashError, gildashError } from '../errors';\nimport { DATA_DIR, DB_FILE } from '../constants';\nimport { invalidateGraphCache } from './graph-api';\nimport type { IDependencyGraphRepo } from '../search/dependency-graph';\nimport type { GildashContext, CoordinatorLike, WatcherLike, DbStore } from './context';\nimport type { GildashOptions, Logger } from './types';\n\n// ─── Constants ──────────────────────────────────────────────────────\n\nexport const HEARTBEAT_INTERVAL_MS = 30_000;\nexport const HEALTHCHECK_INTERVAL_MS = 15_000;\nexport const MAX_HEALTHCHECK_RETRIES = 10;\n\n// ─── Internal Options ───────────────────────────────────────────────\n\nexport interface GildashInternalOptions {\n existsSyncFn?: (p: string) => boolean;\n dbConnectionFactory?: () => DbStore;\n watcherFactory?: () => WatcherLike;\n coordinatorFactory?: () => CoordinatorLike;\n repositoryFactory?: () => {\n fileRepo: Pick<FileRepository, 'upsertFile' | 'getAllFiles' | 'getFilesMap' | 'deleteFile' | 'getFile'>;\n symbolRepo: SymbolRepository;\n relationRepo: RelationRepository;\n parseCache: Pick<ParseCache, 'set' | 'get' | 'invalidate'>;\n };\n acquireWatcherRoleFn?: typeof acquireWatcherRole;\n releaseWatcherRoleFn?: typeof releaseWatcherRole;\n updateHeartbeatFn?: typeof updateHeartbeat;\n discoverProjectsFn?: typeof discoverProjects;\n parseSourceFn?: typeof defaultParseSource;\n extractSymbolsFn?: typeof defaultExtractSymbols;\n extractRelationsFn?: typeof defaultExtractRelations;\n symbolSearchFn?: typeof defaultSymbolSearch;\n relationSearchFn?: typeof defaultRelationSearch;\n patternSearchFn?: (opts: { pattern: string; filePaths: string[] }) => Promise<PatternMatch[]>;\n loadTsconfigPathsFn?: typeof loadTsconfigPaths;\n readFileFn?: (filePath: string) => Promise<string>;\n unlinkFn?: (filePath: string) => Promise<void>;\n semanticLayerFactory?: (tsconfigPath: string) => SemanticLayer;\n}\n\n// ─── Helpers ────────────────────────────────────────────────────────\n\nfunction createWatcherCallback(\n ctx: GildashContext,\n coordinator: CoordinatorLike,\n): (event: FileChangeEvent) => void {\n return (event: FileChangeEvent) => {\n // Fire onFileChanged callbacks\n for (const cb of ctx.onFileChangedCallbacks) {\n try { cb(event); } catch (e) {\n ctx.logger.error('[Gildash] onFileChanged callback threw:', e);\n }\n }\n\n coordinator.handleWatcherEvent?.(event);\n if (ctx.semanticLayer) {\n if (event.eventType === 'delete') {\n try {\n ctx.semanticLayer.notifyFileDeleted(event.filePath);\n } catch (e) {\n ctx.logger.error('[Gildash] semanticLayer.notifyFileDeleted threw:', e);\n for (const cb of ctx.onErrorCallbacks) {\n try { cb(e instanceof GildashError ? e : new GildashError('semantic', 'semantic notifyFileDeleted failed', { cause: e })); } catch { /* protect watcher */ }\n }\n }\n } else {\n ctx.readFileFn(event.filePath).then(content => {\n try {\n ctx.semanticLayer?.notifyFileChanged(event.filePath, content);\n } catch (e) {\n ctx.logger.error('[Gildash] semanticLayer.notifyFileChanged threw:', e);\n for (const cb of ctx.onErrorCallbacks) {\n try { cb(e instanceof GildashError ? e : new GildashError('semantic', 'semantic notifyFileChanged failed', { cause: e })); } catch { /* protect watcher */ }\n }\n }\n }).catch((readErr) => {\n ctx.logger.error('[Gildash] failed to read file for semantic layer', event.filePath, readErr);\n try {\n ctx.semanticLayer?.notifyFileDeleted(event.filePath);\n } catch (e) {\n ctx.logger.error('[Gildash] semanticLayer.notifyFileDeleted threw during read error recovery:', e);\n }\n });\n }\n }\n };\n}\n\nasync function feedSemanticLayer(ctx: GildashContext): Promise<void> {\n if (!ctx.semanticLayer) return;\n const files = ctx.fileRepo.getAllFiles(ctx.defaultProject);\n await Promise.all(\n files.map(async (f) => {\n try {\n const absPath = path.resolve(ctx.projectRoot, f.filePath);\n const content = await ctx.readFileFn(absPath);\n ctx.semanticLayer?.notifyFileChanged(absPath, content);\n } catch { /* best-effort */ }\n }),\n );\n}\n\n/** Create coordinator + watcher, start watcher, heartbeat timer, run fullIndex. */\nexport async function setupOwnerInfrastructure(\n ctx: GildashContext,\n opts: { isWatchMode: boolean },\n): Promise<void> {\n const c: CoordinatorLike = ctx.coordinatorFactory\n ? ctx.coordinatorFactory()\n : new IndexCoordinator({\n projectRoot: ctx.projectRoot,\n boundaries: ctx.boundaries,\n extensions: ctx.extensions,\n ignorePatterns: ctx.ignorePatterns,\n dbConnection: ctx.db,\n parseCache: ctx.parseCache,\n fileRepo: ctx.fileRepo,\n symbolRepo: ctx.symbolRepo,\n relationRepo: ctx.relationRepo,\n logger: ctx.logger,\n });\n\n ctx.coordinator = c;\n\n // (Re-)register any existing callbacks (important for promotion).\n for (const cb of ctx.onIndexedCallbacks) {\n c.onIndexed(cb);\n }\n c.onIndexed((result) => {\n const total = result.changedFiles.length + result.deletedFiles.length;\n if (ctx.graphCache && total > 0 && total < 100) {\n const repo = ctx.relationRepo as unknown as IDependencyGraphRepo;\n ctx.graphCache.patchFiles(result.changedFiles, result.deletedFiles, (filePath) => {\n const projects = [ctx.defaultProject, ...ctx.boundaries.map(b => b.project)];\n return projects.flatMap(p =>\n repo.getByType(p, 'imports')\n .concat(repo.getByType(p, 'type-references'))\n .concat(repo.getByType(p, 're-exports')),\n )\n .filter(r => r.srcFilePath === filePath || r.dstFilePath === filePath)\n .map(r => ({ srcFilePath: r.srcFilePath, dstFilePath: r.dstFilePath }));\n });\n ctx.graphCacheBuiltAt = Date.now();\n } else {\n invalidateGraphCache(ctx);\n }\n });\n\n if (opts.isWatchMode) {\n const w: WatcherLike = ctx.watcherFactory\n ? ctx.watcherFactory()\n : new ProjectWatcher(\n { projectRoot: ctx.projectRoot, ignorePatterns: ctx.ignorePatterns, extensions: ctx.extensions },\n undefined,\n ctx.logger,\n );\n\n await w.start(createWatcherCallback(ctx, c)).then((startResult) => {\n if (isErr(startResult)) throw startResult.data;\n });\n\n ctx.watcher = w;\n\n ctx.timer = setInterval(() => {\n ctx.updateHeartbeatFn(ctx.db, process.pid);\n }, HEARTBEAT_INTERVAL_MS);\n }\n\n await c.fullIndex();\n await feedSemanticLayer(ctx);\n}\n\n/** Register SIGTERM / SIGINT / beforeExit handlers. */\nexport function registerSignalHandlers(\n ctx: GildashContext,\n closeFn: () => Promise<void>,\n): void {\n const signals: Array<NodeJS.Signals | 'beforeExit'> = ['SIGTERM', 'SIGINT', 'beforeExit'];\n for (const sig of signals) {\n const handler = () => {\n closeFn().catch(closeErr =>\n ctx.logger.error('[Gildash] close error during signal', sig, closeErr),\n );\n };\n if (sig === 'beforeExit') {\n process.on('beforeExit', handler);\n } else {\n process.on(sig, handler);\n }\n ctx.signalHandlers.push([sig, handler]);\n }\n}\n\n// ─── Main lifecycle functions ───────────────────────────────────────\n\n/** Initialize a GildashContext (replaces the old `Gildash.open()` body). */\nexport async function initializeContext(\n options: GildashOptions & GildashInternalOptions,\n): Promise<GildashContext> {\n const {\n projectRoot,\n extensions = ['.ts', '.mts', '.cts'],\n ignorePatterns = ['**/node_modules/**'],\n parseCacheCapacity = 500,\n logger = console,\n existsSyncFn = existsSync,\n dbConnectionFactory,\n watcherFactory,\n coordinatorFactory,\n repositoryFactory,\n acquireWatcherRoleFn: acquireWatcherRoleFnOpt = acquireWatcherRole,\n releaseWatcherRoleFn: releaseWatcherRoleFnOpt = releaseWatcherRole,\n updateHeartbeatFn: updateHeartbeatFnOpt = updateHeartbeat,\n discoverProjectsFn = discoverProjects,\n parseSourceFn = defaultParseSource,\n extractSymbolsFn = defaultExtractSymbols,\n extractRelationsFn = defaultExtractRelations,\n symbolSearchFn = defaultSymbolSearch,\n relationSearchFn = defaultRelationSearch,\n patternSearchFn = defaultPatternSearch,\n loadTsconfigPathsFn = loadTsconfigPaths,\n readFileFn = async (fp: string) => Bun.file(fp).text(),\n unlinkFn = async (fp: string) => { await Bun.file(fp).unlink(); },\n watchMode,\n semantic,\n semanticLayerFactory,\n } = options;\n\n if (!path.isAbsolute(projectRoot)) {\n throw new GildashError('validation', `Gildash: projectRoot must be an absolute path, got: \"${projectRoot}\"`);\n }\n if (!existsSyncFn(projectRoot)) {\n throw new GildashError('validation', `Gildash: projectRoot does not exist: \"${projectRoot}\"`);\n }\n\n const db = dbConnectionFactory\n ? dbConnectionFactory()\n : new DbConnection({ projectRoot });\n const openResult = db.open();\n if (isErr(openResult)) throw openResult.data;\n try {\n\n const boundaries = await discoverProjectsFn(projectRoot);\n const defaultProject = boundaries[0]?.project ?? path.basename(projectRoot);\n\n const repos = repositoryFactory\n ? repositoryFactory()\n : (() => {\n const connection = db as DbConnection;\n return {\n fileRepo: new FileRepository(connection),\n symbolRepo: new SymbolRepository(connection),\n relationRepo: new RelationRepository(connection),\n parseCache: new ParseCache(parseCacheCapacity),\n };\n })();\n\n const isWatchMode = watchMode ?? true;\n const instanceId = crypto.randomUUID();\n let role: 'owner' | 'reader';\n if (isWatchMode) {\n role = await Promise.resolve(\n acquireWatcherRoleFnOpt(db, process.pid, { instanceId }),\n );\n } else {\n role = 'owner';\n }\n\n const ctx: GildashContext = {\n projectRoot,\n extensions,\n ignorePatterns,\n logger,\n defaultProject,\n role,\n\n db,\n symbolRepo: repos.symbolRepo,\n relationRepo: repos.relationRepo,\n fileRepo: repos.fileRepo,\n parseCache: repos.parseCache,\n\n releaseWatcherRoleFn: releaseWatcherRoleFnOpt,\n parseSourceFn,\n extractSymbolsFn,\n extractRelationsFn,\n symbolSearchFn,\n relationSearchFn,\n patternSearchFn,\n readFileFn,\n unlinkFn,\n existsSyncFn,\n\n acquireWatcherRoleFn: acquireWatcherRoleFnOpt,\n updateHeartbeatFn: updateHeartbeatFnOpt,\n watcherFactory,\n coordinatorFactory,\n instanceId,\n\n closed: false,\n coordinator: null,\n watcher: null,\n timer: null,\n signalHandlers: [],\n tsconfigPaths: null,\n boundaries,\n onIndexedCallbacks: new Set(),\n onFileChangedCallbacks: new Set(),\n onErrorCallbacks: new Set(),\n onRoleChangedCallbacks: new Set(),\n graphCache: null,\n graphCacheKey: null,\n graphCacheBuiltAt: null,\n semanticLayer: null,\n };\n\n clearTsconfigPathsCache(projectRoot);\n ctx.tsconfigPaths = await loadTsconfigPathsFn(projectRoot);\n\n if (semantic) {\n const tsconfigPath = path.join(projectRoot, 'tsconfig.json');\n try {\n if (semanticLayerFactory) {\n ctx.semanticLayer = semanticLayerFactory(tsconfigPath);\n } else {\n const semanticResult = SemanticLayer.create(tsconfigPath);\n if (isErr(semanticResult)) {\n throw semanticResult.data;\n }\n ctx.semanticLayer = semanticResult;\n }\n } catch (e) {\n if (e instanceof GildashError) throw e;\n throw new GildashError('semantic', 'Gildash: semantic layer creation failed', { cause: e });\n }\n }\n\n if (role === 'owner') {\n await setupOwnerInfrastructure(ctx, { isWatchMode });\n } else {\n // Reader path — healthcheck loop with promotion\n let retryCount = 0;\n const healthcheck = async () => {\n try {\n const newRole = await Promise.resolve(\n ctx.acquireWatcherRoleFn(ctx.db, process.pid, { instanceId: ctx.instanceId }),\n );\n retryCount = 0;\n if (newRole === 'owner') {\n // Fire onRoleChanged callbacks\n for (const cb of ctx.onRoleChangedCallbacks) {\n try { cb('owner'); } catch (e) {\n ctx.logger.error('[Gildash] onRoleChanged callback threw:', e);\n }\n }\n clearInterval(ctx.timer!);\n ctx.timer = null;\n try {\n await setupOwnerInfrastructure(ctx, { isWatchMode: true });\n } catch (setupErr) {\n ctx.logger.error('[Gildash] owner promotion failed, reverting to reader', setupErr);\n if (ctx.watcher) {\n const closeResult = await ctx.watcher.close();\n if (isErr(closeResult)) ctx.logger.error('[Gildash] watcher close error during promotion rollback', closeResult.data);\n ctx.watcher = null;\n }\n if (ctx.coordinator) {\n await ctx.coordinator.shutdown().catch((e) =>\n ctx.logger.error('[Gildash] coordinator shutdown error during promotion rollback', e),\n );\n ctx.coordinator = null;\n }\n if (ctx.timer === null) {\n ctx.timer = setInterval(healthcheck, HEALTHCHECK_INTERVAL_MS);\n }\n }\n }\n } catch (healthErr) {\n retryCount++;\n // Fire onError callbacks\n const gErr = healthErr instanceof GildashError\n ? healthErr\n : new GildashError('watcher', 'Gildash: healthcheck error', { cause: healthErr });\n for (const cb of ctx.onErrorCallbacks) {\n try { cb(gErr); } catch (e) {\n ctx.logger.error('[Gildash] onError callback threw:', e);\n }\n }\n ctx.logger.error('[Gildash] healthcheck error', healthErr);\n if (retryCount >= MAX_HEALTHCHECK_RETRIES) {\n ctx.logger.error('[Gildash] healthcheck failed too many times, shutting down');\n clearInterval(ctx.timer!);\n ctx.timer = null;\n closeContext(ctx).catch((closeErr) =>\n ctx.logger.error('[Gildash] close error during healthcheck shutdown', closeErr),\n );\n }\n }\n };\n ctx.timer = setInterval(healthcheck, HEALTHCHECK_INTERVAL_MS);\n }\n\n if (isWatchMode) {\n registerSignalHandlers(ctx, () => closeContext(ctx));\n }\n\n return ctx;\n } catch (error) {\n db.close();\n if (error instanceof GildashError) throw error;\n throw new GildashError('store', 'Gildash: initialization failed', { cause: error });\n }\n}\n\n/** Shut down the context and release all resources. */\nexport async function closeContext(\n ctx: GildashContext,\n opts?: { cleanup?: boolean },\n): Promise<void> {\n if (ctx.closed) return;\n ctx.closed = true;\n\n const closeErrors: unknown[] = [];\n\n for (const [sig, handler] of ctx.signalHandlers) {\n if (sig === 'beforeExit') {\n process.off('beforeExit', handler);\n } else {\n process.off(sig as NodeJS.Signals, handler);\n }\n }\n ctx.signalHandlers = [];\n\n if (ctx.semanticLayer) {\n try {\n ctx.semanticLayer.dispose();\n } catch (e) {\n closeErrors.push(e instanceof Error ? e : new Error(String(e)));\n }\n ctx.semanticLayer = null;\n }\n\n if (ctx.coordinator) {\n try {\n await ctx.coordinator.shutdown();\n } catch (e) {\n closeErrors.push(e instanceof Error ? e : new Error(String(e)));\n }\n }\n\n if (ctx.watcher) {\n const closeResult = await ctx.watcher.close();\n if (isErr(closeResult)) closeErrors.push(closeResult.data);\n }\n\n if (ctx.timer !== null) {\n clearInterval(ctx.timer);\n ctx.timer = null;\n }\n\n try {\n ctx.releaseWatcherRoleFn(ctx.db, process.pid);\n } catch (e) {\n closeErrors.push(e instanceof Error ? e : new Error(String(e)));\n }\n\n try {\n ctx.db.close();\n } catch (e) {\n closeErrors.push(e instanceof Error ? e : new Error(String(e)));\n }\n\n if (opts?.cleanup) {\n for (const ext of ['', '-wal', '-shm']) {\n try {\n await ctx.unlinkFn(path.join(ctx.projectRoot, DATA_DIR, DB_FILE + ext));\n } catch {}\n }\n }\n\n if (closeErrors.length > 0) {\n throw new GildashError('close', 'Gildash: one or more errors occurred during close()', { cause: closeErrors });\n }\n}\n",
|
|
6
|
-
"import { err, isErr, type Result } from '@zipbul/result';\nimport { Database } from 'bun:sqlite';\nimport { mkdirSync, unlinkSync, existsSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { drizzle, type BunSQLiteDatabase } from 'drizzle-orm/bun-sqlite';\nimport { migrate } from 'drizzle-orm/bun-sqlite/migrator';\nimport { gildashError, type GildashError } from '../errors';\nimport { DATA_DIR, DB_FILE } from '../constants';\nimport * as schema from './schema';\n\n\nexport interface DbConnectionOptions {\n projectRoot: string;\n}\n\nexport class DbConnection {\n private client: Database | null = null;\n private drizzle: BunSQLiteDatabase<typeof schema> | null = null;\n private readonly dbPath: string;\n private txDepth = 0;\n\n constructor(opts: DbConnectionOptions) {\n this.dbPath = join(opts.projectRoot, DATA_DIR, DB_FILE);\n }\n\n get drizzleDb(): BunSQLiteDatabase<typeof schema> {\n if (!this.drizzle) throw new Error('Database is not open. Call open() first.');\n return this.drizzle;\n }\n\n open(): Result<void, GildashError> {\n try {\n mkdirSync(dirname(this.dbPath), { recursive: true });\n this.client = new Database(this.dbPath);\n\n this.client.run('PRAGMA journal_mode = WAL');\n this.client.run('PRAGMA foreign_keys = OFF'); // disabled during migration; re-enabled below\n this.client.run('PRAGMA busy_timeout = 5000');\n\n this.drizzle = drizzle(this.client, { schema });\n\n migrate(this.drizzle, {\n migrationsFolder: join(import.meta.dirname, 'migrations'),\n });\n\n // Verify FK integrity after migration, then re-enable enforcement.\n const violations = this.client.prepare('PRAGMA foreign_key_check').all();\n if (violations.length > 0) {\n throw new Error(\n `FK integrity violation after migration: ${JSON.stringify(violations.slice(0, 5))}`,\n );\n }\n this.client.run('PRAGMA foreign_keys = ON');\n\n // bun:sqlite Database.function() is not available in all Bun versions.\n // Regex filtering falls back to JS-layer post-processing when this is absent.\n const clientAny = this.client as unknown as Record<string, unknown>;\n if (typeof clientAny['function'] === 'function') {\n (clientAny['function'] as Function).call(\n this.client,\n 'regexp',\n (pattern: string, value: string): number => {\n try {\n return new RegExp(pattern).test(value) ? 1 : 0;\n } catch {\n return 0;\n }\n },\n );\n }\n } catch (e) {\n if (this.isCorruptionError(e) && existsSync(this.dbPath)) {\n this.closeClient();\n unlinkSync(this.dbPath);\n for (const ext of ['-wal', '-shm']) {\n const p = this.dbPath + ext;\n if (existsSync(p)) unlinkSync(p);\n }\n const retryResult = this.open();\n if (isErr(retryResult)) {\n return err(gildashError('store', `Failed to recover database at ${this.dbPath}`, retryResult.data));\n }\n return retryResult;\n }\n return err(gildashError('store', `Failed to open database at ${this.dbPath}`, e));\n }\n }\n\n close(): void {\n this.closeClient();\n this.drizzle = null;\n }\n\n transaction<T>(fn: (tx: DbConnection) => T): T {\n const db = this.requireClient();\n\n if (this.txDepth === 0) {\n this.txDepth++;\n try {\n return db.transaction(() => fn(this))();\n } finally {\n this.txDepth--;\n }\n }\n\n const sp = `sp_${this.txDepth++}`;\n db.run(`SAVEPOINT \"${sp}\"`);\n try {\n const result = fn(this);\n db.run(`RELEASE SAVEPOINT \"${sp}\"`);\n return result;\n } catch (err) {\n db.run(`ROLLBACK TO SAVEPOINT \"${sp}\"`);\n db.run(`RELEASE SAVEPOINT \"${sp}\"`);\n throw err;\n } finally {\n this.txDepth--;\n }\n }\n\n immediateTransaction<T>(fn: () => T): T {\n const db = this.requireClient();\n this.txDepth++;\n db.run('BEGIN IMMEDIATE');\n try {\n const result = fn();\n db.run('COMMIT');\n return result;\n } catch (err) {\n db.run('ROLLBACK');\n throw err;\n } finally {\n this.txDepth--;\n }\n }\n\n query(sql: string): unknown {\n const row = this.requireClient().prepare(sql).get() as Record<string, unknown> | null;\n if (!row) return null;\n return Object.values(row)[0];\n }\n\n getTableNames(): string[] {\n const rows = this.requireClient()\n .query(\"SELECT name FROM sqlite_master WHERE type = 'table'\")\n .all() as Array<{ name: string }>;\n return rows.map((r) => r.name);\n }\n\n selectOwner(): { pid: number; heartbeat_at: string; instance_id: string | null } | undefined {\n const row = this.requireClient()\n .prepare('SELECT pid, heartbeat_at, instance_id FROM watcher_owner WHERE id = 1')\n .get() as { pid: number; heartbeat_at: string; instance_id: string | null } | null;\n return row ?? undefined;\n }\n\n insertOwner(pid: number, instanceId?: string): void {\n const now = new Date().toISOString();\n this.requireClient()\n .prepare('INSERT INTO watcher_owner (id, pid, started_at, heartbeat_at, instance_id) VALUES (1, ?, ?, ?, ?)')\n .run(pid, now, now, instanceId ?? null);\n }\n\n replaceOwner(pid: number, instanceId?: string): void {\n const now = new Date().toISOString();\n this.requireClient()\n .prepare('INSERT OR REPLACE INTO watcher_owner (id, pid, started_at, heartbeat_at, instance_id) VALUES (1, ?, ?, ?, ?)')\n .run(pid, now, now, instanceId ?? null);\n }\n\n touchOwner(pid: number): void {\n const now = new Date().toISOString();\n this.requireClient()\n .prepare('UPDATE watcher_owner SET heartbeat_at = ? WHERE id = 1 AND pid = ?')\n .run(now, pid);\n }\n\n deleteOwner(pid: number): void {\n this.requireClient()\n .prepare('DELETE FROM watcher_owner WHERE id = 1 AND pid = ?')\n .run(pid);\n }\n\n private requireClient(): Database {\n if (!this.client) throw new Error('Database is not open. Call open() first.');\n return this.client;\n }\n\n private closeClient(): void {\n if (this.client) {\n this.client.close();\n this.client = null;\n }\n }\n\n private isCorruptionError(err: unknown): boolean {\n if (!(err instanceof Error)) return false;\n const msg = err.message.toLowerCase();\n return (\n msg.includes('malformed') ||\n msg.includes('corrupt') ||\n msg.includes('not a database') ||\n msg.includes('disk i/o error') ||\n msg.includes('sqlite_corrupt')\n );\n }\n}\n",
|
|
7
|
-
"/**\n * Discriminated union type representing all possible error categories in Gildash.\n */\nexport type GildashErrorType =\n | 'watcher'\n | 'parse'\n | 'extract'\n | 'index'\n | 'store'\n | 'search'\n | 'closed'\n | 'validation'\n | 'close'\n | 'semantic';\n\n/**\n * Error class used throughout Gildash.\n * Extends `Error` so that `instanceof Error` checks work and stack traces are captured.\n */\nexport class GildashError extends Error {\n constructor(\n public readonly type: GildashErrorType,\n message: string,\n options?: { cause?: unknown },\n ) {\n super(message, options);\n this.name = 'GildashError';\n }\n}\n\n/**\n * Factory function that creates a {@link GildashError} value.\n *\n * @param type - One of the {@link GildashErrorType} variants.\n * @param message - Human-readable description of the error.\n * @param cause - Optional root cause (any value). When `undefined`, the `cause`\n * property is omitted from the returned object entirely.\n * @deprecated Use `new GildashError(type, message, { cause })` instead.\n */\nexport function gildashError(type: GildashErrorType, message: string, cause?: unknown): GildashError {\n return new GildashError(type, message, cause !== undefined ? { cause } : undefined);\n}\n\n",
|
|
8
|
-
"/** Directory name under projectRoot where gildash stores its SQLite database. */\nexport const DATA_DIR = '.gildash';\n\n/** SQLite database file name inside {@link DATA_DIR}. */\nexport const DB_FILE = 'gildash.db';\n",
|
|
9
|
-
"import { sql } from 'drizzle-orm';\nimport {\n sqliteTable,\n text,\n integer,\n real,\n index,\n primaryKey,\n foreignKey,\n check,\n} from 'drizzle-orm/sqlite-core';\n\nexport const files = sqliteTable(\n 'files',\n {\n project: text('project').notNull(),\n filePath: text('file_path').notNull(),\n mtimeMs: real('mtime_ms').notNull(),\n size: integer('size').notNull(),\n contentHash: text('content_hash').notNull(),\n updatedAt: text('updated_at').notNull(),\n lineCount: integer('line_count'),\n },\n (table) => [primaryKey({ columns: [table.project, table.filePath] })],\n);\n\nexport const symbols = sqliteTable(\n 'symbols',\n {\n id: integer('id').primaryKey({ autoIncrement: true }),\n project: text('project').notNull(),\n filePath: text('file_path').notNull(),\n kind: text('kind').notNull(),\n name: text('name').notNull(),\n startLine: integer('start_line').notNull(),\n startColumn: integer('start_column').notNull(),\n endLine: integer('end_line').notNull(),\n endColumn: integer('end_column').notNull(),\n isExported: integer('is_exported').notNull().default(0),\n signature: text('signature'),\n fingerprint: text('fingerprint'),\n detailJson: text('detail_json'),\n contentHash: text('content_hash').notNull(),\n indexedAt: text('indexed_at').notNull(),\n resolvedType: text('resolved_type'),\n },\n (table) => [\n index('idx_symbols_project_file').on(table.project, table.filePath),\n index('idx_symbols_project_kind').on(table.project, table.kind),\n index('idx_symbols_project_name').on(table.project, table.name),\n index('idx_symbols_fingerprint').on(table.project, table.fingerprint),\n foreignKey({\n columns: [table.project, table.filePath],\n foreignColumns: [files.project, files.filePath],\n }).onDelete('cascade'),\n ],\n);\n\nexport const relations = sqliteTable(\n 'relations',\n {\n id: integer('id').primaryKey({ autoIncrement: true }),\n project: text('project').notNull(),\n type: text('type').notNull(),\n srcFilePath: text('src_file_path').notNull(),\n srcSymbolName: text('src_symbol_name'),\n dstProject: text('dst_project').notNull(),\n dstFilePath: text('dst_file_path').notNull(),\n dstSymbolName: text('dst_symbol_name'),\n metaJson: text('meta_json'),\n },\n (table) => [\n index('idx_relations_src').on(table.project, table.srcFilePath),\n index('idx_relations_dst').on(table.dstProject, table.dstFilePath),\n index('idx_relations_type').on(table.project, table.type),\n index('idx_relations_project_type_src').on(table.project, table.type, table.srcFilePath),\n foreignKey({\n columns: [table.project, table.srcFilePath],\n foreignColumns: [files.project, files.filePath],\n }).onDelete('cascade'),\n foreignKey({\n columns: [table.dstProject, table.dstFilePath],\n foreignColumns: [files.project, files.filePath],\n }).onDelete('cascade'),\n ],\n);\n\nexport const watcherOwner = sqliteTable(\n 'watcher_owner',\n {\n id: integer('id').primaryKey(),\n pid: integer('pid').notNull(),\n startedAt: text('started_at').notNull(),\n heartbeatAt: text('heartbeat_at').notNull(),\n instanceId: text('instance_id'),\n },\n (table) => [check('watcher_owner_singleton', sql`${table.id} = 1`)],\n);\n\n\n",
|
|
10
|
-
"import { eq, and } from 'drizzle-orm';\nimport { files } from '../schema';\nimport type { DbConnection } from '../connection';\n\n/**\n * Metadata record for an indexed source file.\n *\n * Stored and retrieved by {@link FileRepository}.\n * Exposed via {@link Gildash.getFileInfo}.\n */\nexport interface FileRecord {\n /** Project name this file belongs to. */\n project: string;\n /** File path relative to the project root. */\n filePath: string;\n /** Last-modified timestamp in milliseconds since epoch. */\n mtimeMs: number;\n /** File size in bytes at the time of indexing. */\n size: number;\n /** SHA-256 content hash of the file at the time of indexing. */\n contentHash: string;\n /** ISO 8601 timestamp of the last index update. */\n updatedAt: string;\n /** Number of lines in the file at the time of indexing. */\n lineCount?: number | null;\n}\n\nexport class FileRepository {\n constructor(private readonly db: DbConnection) {}\n\n getFile(project: string, filePath: string): FileRecord | null {\n return this.db.drizzleDb\n .select()\n .from(files)\n .where(and(eq(files.project, project), eq(files.filePath, filePath)))\n .get() ?? null;\n }\n\n upsertFile(record: FileRecord): void {\n this.db.drizzleDb\n .insert(files)\n .values({\n project: record.project,\n filePath: record.filePath,\n mtimeMs: record.mtimeMs,\n size: record.size,\n contentHash: record.contentHash,\n updatedAt: record.updatedAt,\n lineCount: record.lineCount ?? null,\n })\n .onConflictDoUpdate({\n target: [files.project, files.filePath],\n set: {\n mtimeMs: record.mtimeMs,\n size: record.size,\n contentHash: record.contentHash,\n updatedAt: record.updatedAt,\n lineCount: record.lineCount ?? null,\n },\n })\n .run();\n }\n\n getAllFiles(project: string): FileRecord[] {\n return this.db.drizzleDb\n .select()\n .from(files)\n .where(eq(files.project, project))\n .all();\n }\n\n getFilesMap(project: string): Map<string, FileRecord> {\n const rows = this.getAllFiles(project);\n const map = new Map<string, FileRecord>();\n for (const r of rows) map.set(r.filePath, r);\n return map;\n }\n\n deleteFile(project: string, filePath: string): void {\n this.db.drizzleDb\n .delete(files)\n .where(and(eq(files.project, project), eq(files.filePath, filePath)))\n .run();\n }\n}\n",
|
|
11
|
-
"import { eq, and, sql, count } from 'drizzle-orm';\nimport { symbols } from '../schema';\nimport type { DbConnection } from '../connection';\nimport { toFtsPrefixQuery } from './fts-utils';\n\nexport interface SymbolRecord {\n project: string;\n filePath: string;\n kind: string;\n name: string;\n startLine: number;\n startColumn: number;\n endLine: number;\n endColumn: number;\n isExported: number;\n signature: string | null;\n fingerprint: string | null;\n detailJson: string | null;\n contentHash: string;\n indexedAt: string;\n resolvedType?: string | null;\n}\n\nexport interface SearchOptions {\n kind?: string;\n limit?: number;\n}\n\n/**\n * Aggregate symbol statistics for a project.\n *\n * Returned by {@link Gildash.getStats}.\n */\nexport interface SymbolStats {\n /** Total number of indexed symbols. */\n symbolCount: number;\n /** Total number of indexed source files. */\n fileCount: number;\n}\n\nexport class SymbolRepository {\n constructor(private readonly db: DbConnection) {}\n\n replaceFileSymbols(\n project: string,\n filePath: string,\n contentHash: string,\n syms: ReadonlyArray<Partial<SymbolRecord>>,\n ): void {\n this.db.drizzleDb\n .delete(symbols)\n .where(and(eq(symbols.project, project), eq(symbols.filePath, filePath)))\n .run();\n\n if (!syms.length) return;\n\n const now = new Date().toISOString();\n for (const sym of syms) {\n this.db.drizzleDb.insert(symbols).values({\n project,\n filePath,\n kind: sym.kind ?? 'unknown',\n name: sym.name ?? '',\n startLine: sym.startLine ?? 0,\n startColumn: sym.startColumn ?? 0,\n endLine: sym.endLine ?? 0,\n endColumn: sym.endColumn ?? 0,\n isExported: sym.isExported ?? 0,\n signature: sym.signature ?? null,\n fingerprint: sym.fingerprint ?? null,\n detailJson: sym.detailJson ?? null,\n contentHash,\n indexedAt: sym.indexedAt ?? now,\n resolvedType: sym.resolvedType ?? null,\n }).run();\n }\n }\n\n getFileSymbols(project: string, filePath: string): SymbolRecord[] {\n return this.db.drizzleDb\n .select()\n .from(symbols)\n .where(and(eq(symbols.project, project), eq(symbols.filePath, filePath)))\n .all();\n }\n\n searchByName(project: string, query: string, opts: SearchOptions = {}): SymbolRecord[] {\n const limit = opts.limit ?? 50;\n const ftsQuery = toFtsPrefixQuery(query);\n\n if (!ftsQuery) return [];\n\n let builder = this.db.drizzleDb\n .select()\n .from(symbols)\n .where(\n and(\n sql`${symbols.id} IN (SELECT rowid FROM symbols_fts WHERE symbols_fts MATCH ${ftsQuery})`,\n eq(symbols.project, project),\n opts.kind ? eq(symbols.kind, opts.kind) : undefined,\n ),\n )\n .orderBy(symbols.name)\n .limit(limit);\n\n return builder.all();\n }\n\n searchByKind(project: string, kind: string): SymbolRecord[] {\n return this.db.drizzleDb\n .select()\n .from(symbols)\n .where(and(eq(symbols.project, project), eq(symbols.kind, kind)))\n .orderBy(symbols.name)\n .all();\n }\n\n getStats(project: string): SymbolStats {\n const row = this.db.drizzleDb\n .select({\n symbolCount: count(),\n fileCount: sql<number>`COUNT(DISTINCT ${symbols.filePath})`,\n })\n .from(symbols)\n .where(eq(symbols.project, project))\n .get();\n return {\n symbolCount: row?.symbolCount ?? 0,\n fileCount: row?.fileCount ?? 0,\n };\n }\n\n getByFingerprint(project: string, fingerprint: string): SymbolRecord[] {\n return this.db.drizzleDb\n .select()\n .from(symbols)\n .where(and(eq(symbols.project, project), eq(symbols.fingerprint, fingerprint)))\n .all();\n }\n\n deleteFileSymbols(project: string, filePath: string): void {\n this.db.drizzleDb\n .delete(symbols)\n .where(and(eq(symbols.project, project), eq(symbols.filePath, filePath)))\n .run();\n }\n\n searchByQuery(opts: {\n ftsQuery?: string;\n exactName?: string;\n kind?: string;\n filePath?: string;\n isExported?: boolean;\n project?: string;\n limit: number;\n decorator?: string;\n regex?: string;\n resolvedType?: string;\n }): (SymbolRecord & { id: number })[] {\n const results = this.db.drizzleDb\n .select()\n .from(symbols)\n .where(\n and(\n opts.ftsQuery\n ? sql`${symbols.id} IN (SELECT rowid FROM symbols_fts WHERE symbols_fts MATCH ${opts.ftsQuery})`\n : undefined,\n opts.exactName ? eq(symbols.name, opts.exactName) : undefined,\n opts.project !== undefined ? eq(symbols.project, opts.project) : undefined,\n opts.kind ? eq(symbols.kind, opts.kind) : undefined,\n opts.filePath !== undefined ? eq(symbols.filePath, opts.filePath) : undefined,\n opts.isExported !== undefined\n ? eq(symbols.isExported, opts.isExported ? 1 : 0)\n : undefined,\n opts.decorator\n ? sql`${symbols.id} IN (SELECT s.id FROM symbols s, json_each(s.detail_json, '$.decorators') je WHERE json_extract(je.value, '$.name') = ${opts.decorator})`\n : undefined,\n opts.resolvedType !== undefined ? eq(symbols.resolvedType, opts.resolvedType) : undefined,\n // NOTE: regex is applied as a JS-layer post-filter below; no SQL condition here.\n ),\n )\n .orderBy(symbols.name)\n // Fetch a larger pool when regex filtering is needed, since JS filtering reduces the result set.\n .limit(opts.regex ? Math.max(opts.limit * 50, 5000) : opts.limit)\n .all() as (SymbolRecord & { id: number })[];\n\n if (!opts.regex) return results;\n\n // JS-layer regex post-filter (SQL REGEXP UDF not available in all Bun versions)\n try {\n const pattern = new RegExp(opts.regex);\n return results.filter(r => pattern.test(r.name)).slice(0, opts.limit) as (SymbolRecord & { id: number })[];\n } catch {\n return [];\n }\n }\n}\n",
|
|
12
|
-
"export function toFtsPrefixQuery(text: string): string {\n return text\n .trim()\n .split(/\\s+/)\n .map((token) => token.trim())\n .filter((token) => token.length > 0)\n .map((token) => `\"${token.replaceAll('\"', '\"\"')}\"*`)\n .join(' ');\n}\n",
|
|
13
|
-
"import { eq, and, isNull, or, sql } from 'drizzle-orm';\nimport { relations as relationsTable } from '../schema';\nimport type { DbConnection } from '../connection';\n\nexport interface RelationRecord {\n project: string;\n type: string;\n srcFilePath: string;\n srcSymbolName: string | null;\n dstProject: string;\n dstFilePath: string;\n dstSymbolName: string | null;\n metaJson: string | null;\n}\n\nexport class RelationRepository {\n constructor(private readonly db: DbConnection) {}\n\n replaceFileRelations(\n project: string,\n srcFilePath: string,\n rels: ReadonlyArray<Partial<RelationRecord>>,\n ): void {\n this.db.transaction((tx) => {\n tx.drizzleDb\n .delete(relationsTable)\n .where(and(eq(relationsTable.project, project), eq(relationsTable.srcFilePath, srcFilePath)))\n .run();\n\n if (!rels.length) return;\n\n for (const rel of rels) {\n tx.drizzleDb.insert(relationsTable).values({\n project,\n type: rel.type ?? 'unknown',\n srcFilePath: rel.srcFilePath ?? srcFilePath,\n srcSymbolName: rel.srcSymbolName ?? null,\n dstProject: rel.dstProject ?? project,\n dstFilePath: rel.dstFilePath ?? '',\n dstSymbolName: rel.dstSymbolName ?? null,\n metaJson: rel.metaJson ?? null,\n }).run();\n }\n });\n }\n\n getOutgoing(project: string, srcFilePath: string, srcSymbolName?: string): RelationRecord[] {\n if (srcSymbolName !== undefined) {\n return this.db.drizzleDb\n .select({\n project: relationsTable.project,\n type: relationsTable.type,\n srcFilePath: relationsTable.srcFilePath,\n srcSymbolName: relationsTable.srcSymbolName,\n dstProject: relationsTable.dstProject,\n dstFilePath: relationsTable.dstFilePath,\n dstSymbolName: relationsTable.dstSymbolName,\n metaJson: relationsTable.metaJson,\n })\n .from(relationsTable)\n .where(\n and(\n eq(relationsTable.project, project),\n eq(relationsTable.srcFilePath, srcFilePath),\n or(\n eq(relationsTable.srcSymbolName, srcSymbolName),\n isNull(relationsTable.srcSymbolName),\n ),\n ),\n )\n .all();\n }\n\n return this.db.drizzleDb\n .select({\n project: relationsTable.project,\n type: relationsTable.type,\n srcFilePath: relationsTable.srcFilePath,\n srcSymbolName: relationsTable.srcSymbolName,\n dstProject: relationsTable.dstProject,\n dstFilePath: relationsTable.dstFilePath,\n dstSymbolName: relationsTable.dstSymbolName,\n metaJson: relationsTable.metaJson,\n })\n .from(relationsTable)\n .where(\n and(\n eq(relationsTable.project, project),\n eq(relationsTable.srcFilePath, srcFilePath),\n ),\n )\n .all();\n }\n\n getIncoming(opts: { dstProject: string; dstFilePath: string }): RelationRecord[] {\n const { dstProject, dstFilePath } = opts;\n return this.db.drizzleDb\n .select({\n project: relationsTable.project,\n type: relationsTable.type,\n srcFilePath: relationsTable.srcFilePath,\n srcSymbolName: relationsTable.srcSymbolName,\n dstProject: relationsTable.dstProject,\n dstFilePath: relationsTable.dstFilePath,\n dstSymbolName: relationsTable.dstSymbolName,\n metaJson: relationsTable.metaJson,\n })\n .from(relationsTable)\n .where(\n and(\n eq(relationsTable.dstProject, dstProject),\n eq(relationsTable.dstFilePath, dstFilePath),\n ),\n )\n .all();\n }\n\n getByType(project: string, type: string): RelationRecord[] {\n return this.db.drizzleDb\n .select({\n project: relationsTable.project,\n type: relationsTable.type,\n srcFilePath: relationsTable.srcFilePath,\n srcSymbolName: relationsTable.srcSymbolName,\n dstProject: relationsTable.dstProject,\n dstFilePath: relationsTable.dstFilePath,\n dstSymbolName: relationsTable.dstSymbolName,\n metaJson: relationsTable.metaJson,\n })\n .from(relationsTable)\n .where(\n and(\n eq(relationsTable.project, project),\n eq(relationsTable.type, type),\n ),\n )\n .all();\n }\n\n deleteFileRelations(project: string, srcFilePath: string): void {\n this.db.drizzleDb\n .delete(relationsTable)\n .where(and(eq(relationsTable.project, project), eq(relationsTable.srcFilePath, srcFilePath)))\n .run();\n }\n\n searchRelations(opts: {\n srcFilePath?: string;\n srcSymbolName?: string;\n dstProject?: string;\n dstFilePath?: string;\n dstSymbolName?: string;\n type?: string;\n project?: string;\n limit: number;\n }): RelationRecord[] {\n return this.db.drizzleDb\n .select({\n project: relationsTable.project,\n type: relationsTable.type,\n srcFilePath: relationsTable.srcFilePath,\n srcSymbolName: relationsTable.srcSymbolName,\n dstProject: relationsTable.dstProject,\n dstFilePath: relationsTable.dstFilePath,\n dstSymbolName: relationsTable.dstSymbolName,\n metaJson: relationsTable.metaJson,\n })\n .from(relationsTable)\n .where(\n and(\n opts.project !== undefined ? eq(relationsTable.project, opts.project) : undefined,\n opts.srcFilePath !== undefined\n ? eq(relationsTable.srcFilePath, opts.srcFilePath)\n : undefined,\n opts.srcSymbolName !== undefined\n ? eq(relationsTable.srcSymbolName, opts.srcSymbolName)\n : undefined,\n opts.dstProject !== undefined\n ? eq(relationsTable.dstProject, opts.dstProject)\n : undefined,\n opts.dstFilePath !== undefined\n ? eq(relationsTable.dstFilePath, opts.dstFilePath)\n : undefined,\n opts.dstSymbolName !== undefined\n ? eq(relationsTable.dstSymbolName, opts.dstSymbolName)\n : undefined,\n opts.type !== undefined ? eq(relationsTable.type, opts.type) : undefined,\n ),\n )\n .limit(opts.limit)\n .all();\n }\n\n retargetRelations(opts: {\n dstProject: string;\n oldFile: string;\n oldSymbol: string | null;\n newFile: string;\n newSymbol: string | null;\n newDstProject?: string;\n }): void {\n const { dstProject, oldFile, oldSymbol, newFile, newSymbol, newDstProject } = opts;\n const condition = oldSymbol === null\n ? and(\n eq(relationsTable.dstProject, dstProject),\n eq(relationsTable.dstFilePath, oldFile),\n isNull(relationsTable.dstSymbolName),\n )\n : and(\n eq(relationsTable.dstProject, dstProject),\n eq(relationsTable.dstFilePath, oldFile),\n eq(relationsTable.dstSymbolName, oldSymbol),\n );\n\n const setValues: { dstFilePath: string; dstSymbolName: string | null; dstProject?: string } = {\n dstFilePath: newFile,\n dstSymbolName: newSymbol,\n };\n if (newDstProject !== undefined) {\n setValues.dstProject = newDstProject;\n }\n\n this.db.drizzleDb\n .update(relationsTable)\n .set(setValues)\n .where(condition)\n .run();\n }\n}\n",
|
|
14
|
-
"import { err, type Result } from '@zipbul/result';\nimport type {\n AsyncSubscription,\n SubscribeCallback,\n} from \"@parcel/watcher\";\nimport { subscribe as parcelSubscribe } from \"@parcel/watcher\";\n\ntype FileEvent = Parameters<SubscribeCallback>[1][number];\ntype SubscribeOptions = NonNullable<Parameters<typeof parcelSubscribe>[2]>;\nimport path from \"node:path\";\nimport { gildashError, type GildashError } from \"../errors\";\nimport type { FileChangeEvent, FileChangeEventType, WatcherOptions } from \"./types\";\nimport type { Logger } from \"../gildash\";\nimport { DATA_DIR } from \"../constants\";\n\ntype SubscribeFn = (\n directoryPath: string,\n callback: SubscribeCallback,\n options?: SubscribeOptions,\n) => Promise<AsyncSubscription>;\n\nconst WATCHER_IGNORE_GLOBS: readonly string[] = [\n \"**/.git/**\",\n `**/${DATA_DIR}/**`,\n \"**/dist/**\",\n \"**/node_modules/**\",\n];\n\nconst CONFIG_FILE_NAMES = new Set([\"package.json\", \"tsconfig.json\"]);\n\nfunction normalizePath(value: string): string {\n return value.replaceAll(\"\\\\\", \"/\");\n}\n\nfunction mapEventType(type: FileEvent[\"type\"]): FileChangeEventType {\n if (type === \"update\") {\n return \"change\";\n }\n\n if (type === \"create\") {\n return \"create\";\n }\n\n return \"delete\";\n}\n\nexport class ProjectWatcher {\n #subscription: AsyncSubscription | undefined;\n #rootPath: string;\n #ignoreGlobs: string[];\n #extensions: Set<string>;\n #subscribe: SubscribeFn;\n #logger: Logger;\n\n constructor(options: WatcherOptions, subscribeFn: SubscribeFn = parcelSubscribe, logger: Logger = console) {\n this.#rootPath = options.projectRoot;\n this.#ignoreGlobs = [...WATCHER_IGNORE_GLOBS, ...(options.ignorePatterns ?? [])];\n this.#extensions = new Set(\n (options.extensions ?? [\".ts\", \".mts\", \".cts\"]).map((ext) =>\n ext.toLowerCase(),\n ),\n );\n this.#subscribe = subscribeFn;\n this.#logger = logger;\n }\n\n async start(onChange: (event: FileChangeEvent) => void): Promise<Result<void, GildashError>> {\n try {\n this.#subscription = await this.#subscribe(\n this.#rootPath,\n (error, events) => {\n if (error) {\n this.#logger.error(gildashError('watcher', 'Callback error', error));\n return;\n }\n\n try {\n for (const rawEvent of events) {\n const relativePath = normalizePath(path.relative(this.#rootPath, rawEvent.path));\n\n if (relativePath.startsWith(\"..\")) {\n continue;\n }\n\n const baseName = path.basename(relativePath);\n const extension = path.extname(relativePath).toLowerCase();\n const isConfigFile = CONFIG_FILE_NAMES.has(baseName);\n\n if (!isConfigFile && !this.#extensions.has(extension)) {\n continue;\n }\n\n if (relativePath.endsWith(\".d.ts\")) {\n continue;\n }\n\n onChange({\n eventType: mapEventType(rawEvent.type),\n filePath: relativePath,\n });\n }\n } catch (callbackError) {\n this.#logger.error(gildashError('watcher', 'Callback error', callbackError));\n }\n },\n {\n ignore: this.#ignoreGlobs,\n },\n );\n } catch (error) {\n return err(gildashError('watcher', 'Failed to subscribe watcher', error));\n }\n }\n\n async close(): Promise<Result<void, GildashError>> {\n if (!this.#subscription) {\n return;\n }\n\n try {\n await this.#subscription.unsubscribe();\n this.#subscription = undefined;\n } catch (error) {\n return err(gildashError('watcher', 'Failed to close watcher', error));\n }\n }\n}\n",
|
|
15
|
-
"import path from \"node:path\";\nimport { promises as fs } from \"node:fs\";\nimport { DATA_DIR } from \"../constants\";\n\n/**\n * A discovered sub-project within the indexed project root.\n *\n * Returned by {@link Gildash.projects}.\n */\nexport interface ProjectBoundary {\n /** Relative directory path from the project root. */\n dir: string;\n /** Unique project name (typically the `name` field from `package.json`). */\n project: string;\n}\n\nconst DISCOVERY_EXCLUDE = [\"**/node_modules/**\", \"**/.git/**\", `**/${DATA_DIR}/**`, \"**/dist/**\"];\n\nexport async function discoverProjects(projectRoot: string): Promise<ProjectBoundary[]> {\n const boundaries: ProjectBoundary[] = [];\n\n for await (const relativePackageJson of fs.glob(\"**/package.json\", {\n cwd: projectRoot,\n exclude: DISCOVERY_EXCLUDE,\n })) {\n const packageDir = path.dirname(relativePackageJson).replaceAll(\"\\\\\", \"/\");\n const packagePath = path.join(projectRoot, relativePackageJson);\n const content = await Bun.file(packagePath).json();\n\n const packageName =\n typeof content?.name === \"string\" && content.name.length > 0\n ? content.name\n : path.basename(packageDir === \".\" ? projectRoot : packageDir);\n\n boundaries.push({\n dir: packageDir,\n project: packageName,\n });\n }\n\n boundaries.sort((left, right) => right.dir.length - left.dir.length);\n return boundaries;\n}\n\nexport function resolveFileProject(\n filePath: string,\n boundaries: ProjectBoundary[],\n rootProject = \"default\",\n): string {\n const normalizedFilePath = filePath.replaceAll(\"\\\\\", \"/\");\n for (const boundary of boundaries) {\n if (boundary.dir === \".\") {\n return boundary.project;\n }\n\n if (\n normalizedFilePath === boundary.dir ||\n normalizedFilePath.startsWith(`${boundary.dir}/`)\n ) {\n return boundary.project;\n }\n }\n\n return rootProject;\n}\n",
|
|
16
|
-
"import path from \"node:path\";\n\nexport interface TsconfigPaths {\n baseUrl: string;\n paths: Map<string, string[]>;\n}\n\nconst cache = new Map<string, TsconfigPaths | null>();\n\nasync function readConfig(configPath: string): Promise<Record<string, unknown> | null> {\n const file = Bun.file(configPath);\n if (!(await file.exists())) {\n return null;\n }\n\n try {\n const text = await file.text();\n const parsed = Bun.JSONC.parse(text);\n return typeof parsed === \"object\" && parsed !== null ? (parsed as Record<string, unknown>) : null;\n } catch {\n return null;\n }\n}\n\nexport async function loadTsconfigPaths(projectRoot: string): Promise<TsconfigPaths | null> {\n if (cache.has(projectRoot)) {\n return cache.get(projectRoot) ?? null;\n }\n\n const tsconfigPath = path.join(projectRoot, \"tsconfig.json\");\n\n const config = await readConfig(tsconfigPath);\n if (!config) {\n cache.set(projectRoot, null);\n return null;\n }\n\n const compilerOptions =\n typeof config.compilerOptions === \"object\" && config.compilerOptions !== null\n ? (config.compilerOptions as Record<string, unknown>)\n : null;\n\n if (!compilerOptions) {\n cache.set(projectRoot, null);\n return null;\n }\n\n const rawBaseUrl = typeof compilerOptions.baseUrl === \"string\" ? compilerOptions.baseUrl : null;\n const rawPaths =\n typeof compilerOptions.paths === \"object\" && compilerOptions.paths !== null\n ? (compilerOptions.paths as Record<string, unknown>)\n : null;\n\n if (!rawBaseUrl && !rawPaths) {\n cache.set(projectRoot, null);\n return null;\n }\n\n const resolvedBaseUrl = rawBaseUrl ? path.resolve(projectRoot, rawBaseUrl) : projectRoot;\n const paths = new Map<string, string[]>();\n\n if (rawPaths) {\n for (const [pattern, targets] of Object.entries(rawPaths)) {\n if (!Array.isArray(targets)) {\n continue;\n }\n\n const normalizedTargets = targets.filter((value): value is string => typeof value === \"string\");\n paths.set(pattern, normalizedTargets);\n }\n }\n\n const result: TsconfigPaths = {\n baseUrl: resolvedBaseUrl,\n paths,\n };\n\n cache.set(projectRoot, result);\n return result;\n}\n\nexport function clearTsconfigPathsCache(projectRoot?: string): void {\n if (projectRoot) {\n cache.delete(projectRoot);\n return;\n }\n\n cache.clear();\n}\n",
|
|
17
|
-
"import path from \"node:path\";\n\nexport function toRelativePath(projectRoot: string, absolutePath: string): string {\n return path.relative(projectRoot, absolutePath).replaceAll(\"\\\\\", \"/\");\n}\n\nexport function toAbsolutePath(projectRoot: string, relativePath: string): string {\n return path.resolve(projectRoot, relativePath);\n}\n",
|
|
18
|
-
"export function hashString(input: string): string {\n const raw = Bun.hash.xxHash64(input);\n const unsigned = BigInt.asUintN(64, BigInt(raw));\n return unsigned.toString(16).padStart(16, \"0\");\n}\n\nexport async function hashFile(filePath: string): Promise<string> {\n const text = await Bun.file(filePath).text();\n return hashString(text);\n}\n",
|
|
19
|
-
"import type { FileChangeEvent } from '../watcher/types';\nimport type { ProjectBoundary } from '../common/project-discovery';\nimport { resolveFileProject, discoverProjects } from '../common/project-discovery';\nimport { loadTsconfigPaths, clearTsconfigPathsCache } from '../common/tsconfig-resolver';\nimport type { TsconfigPaths } from '../common/tsconfig-resolver';\nimport { toAbsolutePath } from '../common/path-utils';\nimport { hashString } from '../common/hasher';\nimport { isErr } from '@zipbul/result';\nimport { parseSource } from '../parser/parse-source';\nimport type { ParsedFile } from '../parser/types';\nimport { detectChanges } from './file-indexer';\nimport { indexFileSymbols } from './symbol-indexer';\nimport { indexFileRelations } from './relation-indexer';\nimport type { DbConnection } from '../store/connection';\nimport type { FileRecord } from '../store/repositories/file.repository';\nimport type { SymbolRecord } from '../store/repositories/symbol.repository';\nimport type { RelationRecord } from '../store/repositories/relation.repository';\nimport type { Logger } from '../gildash';\n\nexport const WATCHER_DEBOUNCE_MS = 100;\nexport const FILE_READ_BATCH_SIZE = 50;\n\n/**\n * Summary returned after an indexing run completes.\n *\n * Received via {@link Gildash.reindex} and the {@link Gildash.onIndexed} callback.\n */\nexport interface IndexResult {\n /** Number of files that were (re-)indexed. */\n indexedFiles: number;\n /** Number of files removed from the index. */\n removedFiles: number;\n /** Total symbol count after indexing. */\n totalSymbols: number;\n /** Total relation count after indexing. */\n totalRelations: number;\n /** Wall-clock duration of the indexing run in milliseconds. */\n durationMs: number;\n /** Absolute paths of files that changed and were re-indexed. */\n changedFiles: string[];\n /** Absolute paths of files that were deleted from the index. */\n deletedFiles: string[];\n /** Absolute paths of files that failed to index. */\n failedFiles: string[];\n /**\n * Symbol-level diff compared to the previous index state.\n * On the very first full index (empty DB), all symbols appear in `added`.\n */\n changedSymbols: {\n added: Array<{ name: string; filePath: string; kind: string }>;\n modified: Array<{ name: string; filePath: string; kind: string }>;\n removed: Array<{ name: string; filePath: string; kind: string }>;\n };\n}\n\nexport interface IndexCoordinatorOptions {\n projectRoot: string;\n boundaries: ProjectBoundary[];\n extensions: string[];\n ignorePatterns: string[];\n dbConnection: { transaction<T>(fn: (tx: DbConnection) => T): T };\n parseCache: {\n set(key: string, value: unknown): void;\n get(key: string): unknown;\n invalidate(key: string): void;\n };\n fileRepo: {\n getFilesMap(project: string): Map<string, FileRecord>;\n getAllFiles(project: string): FileRecord[];\n upsertFile(record: FileRecord): void;\n deleteFile(project: string, filePath: string): void;\n };\n symbolRepo: {\n replaceFileSymbols(project: string, filePath: string, contentHash: string, symbols: ReadonlyArray<Partial<SymbolRecord>>): void;\n getFileSymbols(project: string, filePath: string): SymbolRecord[];\n getByFingerprint(project: string, fingerprint: string): SymbolRecord[];\n deleteFileSymbols(project: string, filePath: string): void;\n };\n relationRepo: {\n replaceFileRelations(project: string, filePath: string, relations: ReadonlyArray<Partial<RelationRecord>>): void;\n retargetRelations(opts: { dstProject: string; oldFile: string; oldSymbol: string | null; newFile: string; newSymbol: string | null; newDstProject?: string }): void;\n deleteFileRelations(project: string, filePath: string): void;\n };\n parseSourceFn?: typeof parseSource;\n discoverProjectsFn?: typeof discoverProjects;\n logger?: Logger;\n}\n\nexport class IndexCoordinator {\n private readonly opts: IndexCoordinatorOptions;\n private readonly logger: Logger;\n\n private readonly callbacks = new Set<(result: IndexResult) => void>();\n\n private indexingLock = false;\n\n private pendingEvents: FileChangeEvent[] = [];\n\n private debounceTimer: ReturnType<typeof setTimeout> | null = null;\n\n private currentIndexing: Promise<IndexResult> | null = null;\n\n private pendingFullIndex = false;\n\n private pendingFullIndexWaiters: Array<{ resolve: (r: IndexResult) => void; reject: (e: unknown) => void }> = [];\n\n private tsconfigPathsRaw: Promise<TsconfigPaths | null>;\n\n private boundariesRefresh: Promise<void> | null = null;\n\n constructor(opts: IndexCoordinatorOptions) {\n this.opts = opts;\n this.logger = opts.logger ?? console;\n this.tsconfigPathsRaw = loadTsconfigPaths(opts.projectRoot);\n }\n\n get tsconfigPaths(): Promise<TsconfigPaths | null> {\n return this.tsconfigPathsRaw;\n }\n\n fullIndex(): Promise<IndexResult> {\n return this.startIndex(undefined, true);\n }\n\n incrementalIndex(events?: FileChangeEvent[]): Promise<IndexResult> {\n return this.startIndex(events, false);\n }\n\n onIndexed(cb: (result: IndexResult) => void): () => void {\n this.callbacks.add(cb);\n return () => this.callbacks.delete(cb);\n }\n\n handleWatcherEvent(event: FileChangeEvent): void {\n if (event.filePath.endsWith('tsconfig.json')) {\n clearTsconfigPathsCache(this.opts.projectRoot);\n this.tsconfigPathsRaw = loadTsconfigPaths(this.opts.projectRoot);\n this.fullIndex().catch((err) => {\n this.logger.error('[IndexCoordinator] fullIndex failed after tsconfig change:', err);\n });\n return;\n }\n\n if (event.filePath.endsWith('package.json')) {\n const discover = this.opts.discoverProjectsFn ?? discoverProjects;\n this.boundariesRefresh = discover(this.opts.projectRoot).then((b) => {\n this.opts.boundaries = b;\n });\n }\n\n this.pendingEvents.push(event);\n\n if (this.debounceTimer === null) {\n this.debounceTimer = setTimeout(() => {\n this.debounceTimer = null;\n this.flushPending();\n }, WATCHER_DEBOUNCE_MS);\n }\n }\n\n async shutdown(): Promise<void> {\n if (this.debounceTimer !== null) {\n clearTimeout(this.debounceTimer);\n this.debounceTimer = null;\n }\n if (this.currentIndexing) {\n await this.currentIndexing;\n }\n }\n\n private startIndex(events: FileChangeEvent[] | undefined, useTransaction: boolean): Promise<IndexResult> {\n if (this.indexingLock) {\n if (useTransaction) {\n this.pendingFullIndex = true;\n return new Promise<IndexResult>((resolve, reject) => {\n this.pendingFullIndexWaiters.push({ resolve, reject });\n });\n }\n return this.currentIndexing!;\n }\n this.indexingLock = true;\n\n const work = this.doIndex(events, useTransaction)\n .then((result) => {\n this.fireCallbacks(result);\n return result;\n })\n .finally(() => {\n this.indexingLock = false;\n this.currentIndexing = null;\n if (this.pendingFullIndex) {\n this.pendingFullIndex = false;\n const waiters = this.pendingFullIndexWaiters.splice(0);\n this.startIndex(undefined, true)\n .then((result) => {\n for (const waiter of waiters) waiter.resolve(result);\n })\n .catch((error) => {\n for (const waiter of waiters) waiter.reject(error);\n });\n } else if (this.pendingEvents.length > 0) {\n const drained = this.pendingEvents.splice(0);\n this.startIndex(drained, false).catch((err) =>\n this.logger.error('[IndexCoordinator] incremental drain error', err),\n );\n }\n });\n\n this.currentIndexing = work;\n return work;\n }\n\n private async doIndex(events: FileChangeEvent[] | undefined, useTransaction: boolean): Promise<IndexResult> {\n const start = Date.now();\n const { fileRepo, symbolRepo, relationRepo, dbConnection } = this.opts;\n\n if (this.boundariesRefresh) {\n await this.boundariesRefresh;\n this.boundariesRefresh = null;\n }\n\n let changed: Array<{ filePath: string; contentHash: string; mtimeMs: number; size: number }>;\n let deleted: string[];\n\n if (events !== undefined) {\n changed = events\n .filter((e) => e.eventType === 'create' || e.eventType === 'change')\n .map((e) => ({\n filePath: e.filePath,\n contentHash: '',\n mtimeMs: 0,\n size: 0,\n }));\n deleted = events.filter((e) => e.eventType === 'delete').map((e) => e.filePath);\n } else {\n const existingMap = new Map<string, FileRecord>();\n for (const boundary of this.opts.boundaries) {\n for (const [key, val] of fileRepo.getFilesMap(boundary.project)) {\n existingMap.set(key, val);\n }\n }\n const result = await detectChanges({\n projectRoot: this.opts.projectRoot,\n extensions: this.opts.extensions,\n ignorePatterns: this.opts.ignorePatterns,\n fileRepo: { getFilesMap: () => existingMap },\n });\n changed = result.changed;\n deleted = result.deleted;\n }\n\n const tsconfigPaths = (await this.tsconfigPathsRaw) ?? undefined;\n\n const deletedSymbols = new Map<string, SymbolRecord[]>();\n for (const filePath of deleted) {\n const project = resolveFileProject(filePath, this.opts.boundaries);\n const syms = symbolRepo.getFileSymbols(project, filePath);\n deletedSymbols.set(filePath, syms);\n }\n\n // FR-08: collect before-indexing symbol snapshot for changedSymbols diff\n type SymbolSnap = { name: string; filePath: string; kind: string; fingerprint: string | null };\n const beforeSnapshot = new Map<string, SymbolSnap>();\n const afterSnapshot = new Map<string, SymbolSnap>();\n\n if (useTransaction) {\n // fullIndex: snapshot all currently-stored symbols before the transaction wipes them\n for (const boundary of this.opts.boundaries) {\n for (const f of fileRepo.getAllFiles(boundary.project)) {\n for (const sym of symbolRepo.getFileSymbols(boundary.project, f.filePath)) {\n beforeSnapshot.set(`${sym.filePath}::${sym.name}`, {\n name: sym.name, filePath: sym.filePath, kind: sym.kind, fingerprint: sym.fingerprint,\n });\n }\n }\n }\n } else {\n // incremental: snapshot symbols in files that are about to change\n for (const file of changed) {\n const project = resolveFileProject(file.filePath, this.opts.boundaries);\n for (const sym of symbolRepo.getFileSymbols(project, file.filePath)) {\n beforeSnapshot.set(`${sym.filePath}::${sym.name}`, {\n name: sym.name, filePath: sym.filePath, kind: sym.kind, fingerprint: sym.fingerprint,\n });\n }\n }\n // also include symbols from files being deleted\n for (const [, syms] of deletedSymbols) {\n for (const sym of syms) {\n beforeSnapshot.set(`${sym.filePath}::${sym.name}`, {\n name: sym.name, filePath: sym.filePath, kind: sym.kind, fingerprint: sym.fingerprint,\n });\n }\n }\n }\n\n const processDeleted = () => {\n for (const filePath of deleted) {\n const project = resolveFileProject(filePath, this.opts.boundaries);\n symbolRepo.deleteFileSymbols(project, filePath);\n relationRepo.deleteFileRelations(project, filePath);\n fileRepo.deleteFile(project, filePath);\n }\n };\n\n const processChanged = async (): Promise<{ symbols: number; relations: number; failedFiles: string[] }> => {\n const { projectRoot, boundaries } = this.opts;\n const { parseCache } = this.opts;\n let symbols = 0;\n let relations = 0;\n const failedFiles: string[] = [];\n\n // ── Pass 1: 모든 변경 파일 read + parse + upsertFile ──\n type Prepared = {\n filePath: string; text: string; contentHash: string;\n parsed: ParsedFile; project: string;\n };\n const prepared: Prepared[] = [];\n\n for (const file of changed) {\n try {\n const absPath = toAbsolutePath(projectRoot, file.filePath);\n const bunFile = Bun.file(absPath);\n const text = await bunFile.text();\n const contentHash = file.contentHash || hashString(text);\n const project = resolveFileProject(file.filePath, boundaries);\n\n fileRepo.upsertFile({\n project,\n filePath: file.filePath,\n mtimeMs: bunFile.lastModified,\n size: bunFile.size,\n contentHash,\n updatedAt: new Date().toISOString(),\n lineCount: text.split('\\n').length,\n });\n\n const parseFn = this.opts.parseSourceFn ?? parseSource;\n const parseResult = parseFn(absPath, text);\n if (isErr(parseResult)) throw parseResult.data;\n const parsed = parseResult as ParsedFile;\n prepared.push({ filePath: file.filePath, text, contentHash, parsed, project });\n } catch (e) {\n this.logger.error(`[IndexCoordinator] Failed to prepare ${file.filePath}:`, e);\n failedFiles.push(file.filePath);\n }\n }\n\n // ── knownFiles 구축 (1회) — Pass 1 완료 후 모든 신규 파일 포함 ──\n const knownFiles = new Set<string>();\n for (const boundary of boundaries) {\n for (const [fp] of fileRepo.getFilesMap(boundary.project)) {\n knownFiles.add(`${boundary.project}::${fp}`);\n }\n }\n\n // ── Pass 2: index symbols + relations (동기 DB → 트랜잭션으로 보호) ──\n dbConnection.transaction(() => {\n for (const fd of prepared) {\n indexFileSymbols({\n parsed: fd.parsed, project: fd.project,\n filePath: fd.filePath, contentHash: fd.contentHash, symbolRepo,\n });\n relations += indexFileRelations({\n ast: fd.parsed.program, project: fd.project, filePath: fd.filePath,\n relationRepo, projectRoot, tsconfigPaths,\n knownFiles, boundaries,\n });\n parseCache.set(fd.filePath, fd.parsed);\n symbols += symbolRepo.getFileSymbols(fd.project, fd.filePath).length;\n }\n });\n\n return { symbols, relations, failedFiles };\n };\n\n let totalSymbols = 0;\n let totalRelations = 0;\n let allFailedFiles: string[] = [];\n\n if (useTransaction) {\n const { projectRoot, boundaries } = this.opts;\n const { parseCache } = this.opts;\n type PrereadEntry = { filePath: string; text: string; contentHash: string; mtimeMs: number; size: number };\n const preread: PrereadEntry[] = [];\n for (let i = 0; i < changed.length; i += FILE_READ_BATCH_SIZE) {\n const chunk = changed.slice(i, i + FILE_READ_BATCH_SIZE);\n const chunkResults = await Promise.allSettled(\n chunk.map(async (file) => {\n const absPath = toAbsolutePath(projectRoot, file.filePath);\n const bunFile = Bun.file(absPath);\n const text = await bunFile.text();\n const contentHash = file.contentHash || hashString(text);\n return { filePath: file.filePath, text, contentHash, mtimeMs: bunFile.lastModified, size: bunFile.size };\n }),\n );\n for (const r of chunkResults) {\n if (r.status === 'fulfilled') {\n preread.push(r.value);\n } else {\n this.logger.error('[IndexCoordinator] Failed to pre-read file:', r.reason);\n }\n }\n }\n\n const parsedCacheEntries: Array<{ filePath: string; parsed: unknown }> = [];\n\n dbConnection.transaction(() => {\n // Only delete changed files (cascade removes their symbols + relations).\n // Unchanged files are preserved so that FK constraints on\n // relations.dstFilePath remain satisfiable.\n for (const fd of preread) {\n const project = resolveFileProject(fd.filePath, boundaries);\n fileRepo.deleteFile(project, fd.filePath);\n }\n for (const filePath of deleted) {\n const project = resolveFileProject(filePath, boundaries);\n symbolRepo.deleteFileSymbols(project, filePath);\n relationRepo.deleteFileRelations(project, filePath);\n fileRepo.deleteFile(project, filePath);\n }\n\n // Pass 1: Insert all file records first so that FK constraints on\n // relations.dstFilePath are satisfiable regardless of processing order.\n for (const fd of preread) {\n const project = resolveFileProject(fd.filePath, boundaries);\n fileRepo.upsertFile({\n project,\n filePath: fd.filePath,\n mtimeMs: fd.mtimeMs,\n size: fd.size,\n contentHash: fd.contentHash,\n updatedAt: new Date().toISOString(),\n lineCount: fd.text.split('\\n').length,\n });\n }\n\n // knownFiles Set 구축: Pass 1에서 upsert한 파일 + 기존 파일 모두 포함 (read-your-own-writes)\n const knownFiles = new Set<string>();\n for (const boundary of boundaries) {\n for (const [fp] of fileRepo.getFilesMap(boundary.project)) {\n knownFiles.add(`${boundary.project}::${fp}`);\n }\n }\n\n // Pass 2: Parse sources and index symbols + relations.\n const parseFn = this.opts.parseSourceFn ?? parseSource;\n for (const fd of preread) {\n const project = resolveFileProject(fd.filePath, boundaries);\n const parseResult = parseFn(toAbsolutePath(projectRoot, fd.filePath), fd.text);\n if (isErr(parseResult)) throw parseResult.data;\n const parsed = parseResult;\n parsedCacheEntries.push({ filePath: fd.filePath, parsed });\n indexFileSymbols({ parsed, project, filePath: fd.filePath, contentHash: fd.contentHash, symbolRepo });\n totalRelations += indexFileRelations({\n ast: parsed.program,\n project,\n filePath: fd.filePath,\n relationRepo,\n projectRoot,\n tsconfigPaths,\n knownFiles,\n boundaries,\n });\n totalSymbols += symbolRepo.getFileSymbols(project, fd.filePath).length;\n }\n });\n\n for (const entry of parsedCacheEntries) {\n parseCache.set(entry.filePath, entry.parsed);\n }\n } else {\n processDeleted();\n const counts = await processChanged();\n totalSymbols = counts.symbols;\n totalRelations = counts.relations;\n allFailedFiles = counts.failedFiles;\n }\n\n // FR-08: collect after-indexing symbol snapshot\n for (const file of changed) {\n const project = resolveFileProject(file.filePath, this.opts.boundaries);\n for (const sym of symbolRepo.getFileSymbols(project, file.filePath)) {\n afterSnapshot.set(`${sym.filePath}::${sym.name}`, {\n name: sym.name, filePath: sym.filePath, kind: sym.kind, fingerprint: sym.fingerprint,\n });\n }\n }\n\n // FR-08: compute symbol-level diff (added / modified / removed)\n const changedSymbols: IndexResult['changedSymbols'] = { added: [], modified: [], removed: [] };\n for (const [key, after] of afterSnapshot) {\n const before = beforeSnapshot.get(key);\n if (!before) {\n changedSymbols.added.push({ name: after.name, filePath: after.filePath, kind: after.kind });\n } else if (before.fingerprint !== after.fingerprint) {\n changedSymbols.modified.push({ name: after.name, filePath: after.filePath, kind: after.kind });\n }\n }\n for (const [key, before] of beforeSnapshot) {\n if (!afterSnapshot.has(key)) {\n changedSymbols.removed.push({ name: before.name, filePath: before.filePath, kind: before.kind });\n }\n }\n\n if (!useTransaction) {\n for (const [oldFile, syms] of deletedSymbols) {\n for (const sym of syms) {\n if (!sym.fingerprint) continue;\n const oldProject = resolveFileProject(oldFile, this.opts.boundaries);\n const matches = symbolRepo.getByFingerprint(oldProject, sym.fingerprint);\n if (matches.length === 1) {\n const newSym = matches[0]!;\n relationRepo.retargetRelations({\n dstProject: oldProject,\n oldFile,\n oldSymbol: sym.name,\n newFile: newSym.filePath,\n newSymbol: newSym.name,\n });\n }\n }\n }\n }\n\n return {\n indexedFiles: changed.length,\n removedFiles: deleted.length,\n totalSymbols,\n totalRelations,\n durationMs: Date.now() - start,\n changedFiles: changed.map((f) => f.filePath),\n deletedFiles: [...deleted],\n failedFiles: allFailedFiles,\n changedSymbols,\n };\n }\n\n private fireCallbacks(result: IndexResult): void {\n for (const cb of this.callbacks) {\n try {\n cb(result);\n } catch (err) {\n this.logger.error('[IndexCoordinator] onIndexed callback threw:', err);\n }\n }\n }\n\n private flushPending(): void {\n if (this.indexingLock) {\n return;\n }\n if (this.pendingEvents.length > 0) {\n const events = this.pendingEvents.splice(0);\n this.startIndex(events, false).catch((err) =>\n this.logger.error('[IndexCoordinator] flushPending startIndex error:', err),\n );\n }\n }\n}\n",
|
|
20
|
-
"import { err, type Result } from '@zipbul/result';\nimport { parseSync as defaultParseSync } from 'oxc-parser';\nimport type { ParserOptions } from 'oxc-parser';\nimport type { ParsedFile } from './types';\nimport { gildashError, type GildashError } from '../errors';\n\nexport function parseSource(\n filePath: string,\n sourceText: string,\n options?: ParserOptions,\n parseSyncFn: typeof defaultParseSync = defaultParseSync,\n): Result<ParsedFile, GildashError> {\n try {\n const { program, errors, comments } = parseSyncFn(filePath, sourceText, options);\n return { filePath, program: program as ParsedFile['program'], errors, comments, sourceText };\n } catch (e) {\n return err(gildashError('parse', `Failed to parse file: ${filePath}`, e));\n }\n}\n",
|
|
21
|
-
"import { promises as fsPromises } from 'node:fs';\nimport { join } from 'node:path';\nimport { hashString } from '../common/hasher';\n\nexport interface FileChangeRecord {\n filePath: string;\n contentHash: string;\n mtimeMs: number;\n size: number;\n}\n\nexport interface DetectChangesResult {\n changed: FileChangeRecord[];\n unchanged: FileChangeRecord[];\n deleted: string[];\n}\n\ninterface FileRepoPart {\n getFilesMap(): Map<string, { filePath: string; mtimeMs: number; size: number; contentHash: string }>;\n}\n\nexport interface DetectChangesOptions {\n projectRoot: string;\n extensions: string[];\n ignorePatterns: string[];\n fileRepo: FileRepoPart;\n}\n\nexport async function detectChanges(opts: DetectChangesOptions): Promise<DetectChangesResult> {\n const { projectRoot, extensions, ignorePatterns, fileRepo } = opts;\n\n const existingMap = fileRepo.getFilesMap();\n const seenPaths = new Set<string>();\n const changed: FileChangeRecord[] = [];\n const unchanged: FileChangeRecord[] = [];\n\n const ignoreGlobs = ignorePatterns.map((p) => new Bun.Glob(p));\n\n for await (const relativePath of fsPromises.glob('**/*', { cwd: projectRoot })) {\n if (!extensions.some((ext) => relativePath.endsWith(ext))) continue;\n\n if (relativePath.startsWith('node_modules/') || relativePath.includes('/node_modules/')) continue;\n\n if (ignoreGlobs.some((g) => g.match(relativePath))) continue;\n\n seenPaths.add(relativePath);\n\n const absPath = join(projectRoot, relativePath);\n const bunFile = Bun.file(absPath);\n const { size, lastModified: mtimeMs } = bunFile;\n\n const existing = existingMap.get(relativePath);\n\n if (!existing) {\n const text = await bunFile.text();\n const contentHash = hashString(text);\n changed.push({ filePath: relativePath, contentHash, mtimeMs, size });\n continue;\n }\n\n if (existing.mtimeMs === mtimeMs && existing.size === size) {\n unchanged.push({ filePath: relativePath, contentHash: existing.contentHash, mtimeMs, size });\n continue;\n }\n\n const text = await bunFile.text();\n const contentHash = hashString(text);\n if (contentHash === existing.contentHash) {\n unchanged.push({ filePath: relativePath, contentHash, mtimeMs, size });\n } else {\n changed.push({ filePath: relativePath, contentHash, mtimeMs, size });\n }\n }\n\n const deleted: string[] = [];\n for (const filePath of existingMap.keys()) {\n if (!seenPaths.has(filePath)) {\n deleted.push(filePath);\n }\n }\n\n return { changed, unchanged, deleted };\n}\n",
|
|
22
|
-
"import type { SourcePosition } from './types';\n\nexport function buildLineOffsets(sourceText: string): number[] {\n const offsets: number[] = [0];\n for (let i = 0; i < sourceText.length; i++) {\n if (sourceText[i] === '\\n') {\n offsets.push(i + 1);\n }\n }\n return offsets;\n}\n\nexport function getLineColumn(offsets: number[], offset: number): SourcePosition {\n let lo = 0;\n let hi = offsets.length - 1;\n while (lo < hi) {\n const mid = (lo + hi + 1) >> 1;\n if (offsets[mid]! <= offset) {\n lo = mid;\n } else {\n hi = mid - 1;\n }\n }\n return { line: lo + 1, column: offset - offsets[lo]! };\n}\n",
|
|
23
|
-
"import { err, type Result } from '@zipbul/result';\nimport { parse } from 'comment-parser';\nimport type { JsDocBlock } from '../extractor/types';\nimport { gildashError, type GildashError } from '../errors';\n\nexport function parseJsDoc(commentText: string): Result<JsDocBlock, GildashError> {\n try {\n let stripped = commentText.trim();\n if (stripped.startsWith('/**')) stripped = stripped.slice(3);\n if (stripped.endsWith('*/')) stripped = stripped.slice(0, -2);\n\n const blocks = parse(`/** ${stripped} */`);\n const block = blocks[0] ?? { description: '', tags: [] };\n\n return {\n description: (block.description ?? '').trim(),\n tags: (block.tags ?? []).map((t) => ({\n tag: t.tag ?? '',\n name: t.name ?? '',\n type: t.type ?? '',\n description: t.description ?? '',\n optional: t.optional ?? false,\n ...(t.default !== undefined ? { default: t.default } : {}),\n })),\n };\n } catch (e) {\n return err(gildashError('parse', 'Failed to parse JSDoc comment', e));\n }\n}\n",
|
|
24
|
-
"import type { ParsedFile } from '../parser/types';\nimport type { SourceSpan } from '../parser/types';\nimport type {\n ExtractedSymbol,\n SymbolKind,\n Modifier,\n Heritage,\n Parameter,\n Decorator,\n} from './types';\nimport { buildLineOffsets, getLineColumn } from '../parser/source-position';\nimport { parseJsDoc } from '../parser/jsdoc-parser';\nimport { isErr } from '@zipbul/result';\n\ntype OxcSpan = { start: number; end: number };\n\ntype OxcTypeAnn = OxcSpan & { typeAnnotation?: OxcSpan };\n\ntype OxcDeco = OxcSpan & {\n expression?: OxcSpan & {\n type?: string;\n callee?: { name?: string; property?: { name?: string } };\n arguments?: OxcSpan[];\n name?: string;\n };\n};\n\ntype OxcParam = OxcSpan & {\n type?: string;\n name?: string;\n optional?: boolean;\n typeAnnotation?: OxcTypeAnn;\n decorators?: OxcDeco[];\n parameter?: OxcParam;\n argument?: OxcParam & { name?: string };\n left?: OxcParam;\n right?: OxcSpan;\n pattern?: { name?: string };\n};\n\ntype OxcModNode = {\n static?: boolean;\n abstract?: boolean;\n readonly?: boolean;\n override?: boolean;\n declare?: boolean;\n const?: boolean;\n accessibility?: string;\n async?: boolean;\n};\n\ntype OxcMember = OxcSpan & OxcModNode & {\n type?: string;\n key?: { name?: string };\n value?: OxcSpan & OxcModNode & { params?: OxcParam[]; returnType?: OxcTypeAnn };\n kind?: string;\n params?: OxcParam[];\n returnType?: OxcTypeAnn;\n typeAnnotation?: OxcTypeAnn;\n};\n\ntype OxcNode = OxcSpan & OxcModNode & {\n type?: string;\n name?: string;\n id?: { name?: string };\n params?: OxcParam[];\n returnType?: OxcTypeAnn;\n typeAnnotation?: OxcTypeAnn;\n body?: {\n body?: OxcMember[];\n members?: Array<OxcSpan & { id?: { name?: string; value?: string } }>;\n };\n decorators?: OxcDeco[];\n typeParameters?: { params?: Array<{ name?: { name?: string } }> };\n superClass?: OxcSpan;\n implements?: Array<OxcSpan & { expression?: OxcSpan }>;\n extends?: Array<OxcSpan & { expression?: OxcSpan }>;\n declarations?: Array<OxcSpan & {\n id?: OxcNode & {\n properties?: Array<OxcSpan & { value?: { name?: string }; key?: { name?: string } }>;\n elements?: Array<(OxcSpan & { type?: string; name?: string }) | null>;\n };\n init?: OxcNode;\n }>;\n};\n\nexport function extractSymbols(parsed: ParsedFile): ExtractedSymbol[] {\n const { program, sourceText, comments } = parsed;\n const lineOffsets = buildLineOffsets(sourceText);\n\n function span(start: number, end: number): SourceSpan {\n return {\n start: getLineColumn(lineOffsets, start),\n end: getLineColumn(lineOffsets, end),\n };\n }\n\n function findJsDocComment(nodeStart: number): string | undefined {\n let best: { value: string; end: number } | null = null;\n for (const c of comments) {\n if (c.type !== 'Block') continue;\n if (c.end > nodeStart) continue;\n if (!c.value.startsWith('*')) continue;\n if (!best || c.end > best.end) {\n best = { value: `/*${c.value}*/`, end: c.end };\n }\n }\n if (!best) return undefined;\n\n for (const stmt of program.body) {\n const stmtStart = (stmt as { start?: number }).start ?? 0;\n if (stmtStart === nodeStart) continue;\n if (stmtStart > best.end && stmtStart < nodeStart) {\n return undefined;\n }\n }\n\n return best.value;\n }\n\n function typeText(typeAnnotation: OxcTypeAnn | null | undefined): string | undefined {\n if (!typeAnnotation) return undefined;\n const inner = typeAnnotation.typeAnnotation ?? typeAnnotation;\n return sourceText.slice(inner.start, inner.end);\n }\n\n function extractDecorators(decorators: OxcDeco[]): Decorator[] {\n if (!decorators || decorators.length === 0) return [];\n return decorators.map((d) => {\n const expr = d.expression;\n if (!expr) return { name: 'unknown' };\n if (expr.type === 'CallExpression') {\n const name = expr.callee?.name ?? expr.callee?.property?.name ?? 'unknown';\n const args = (expr.arguments ?? []).map((a: OxcSpan) => sourceText.slice(a.start, a.end));\n return { name, arguments: args.length > 0 ? args : undefined };\n }\n if (expr.type === 'Identifier') return { name: expr.name ?? 'unknown' };\n return { name: sourceText.slice(expr.start, expr.end) };\n });\n }\n\n function extractParam(p: OxcParam): Parameter {\n const inner = p.type === 'TSParameterProperty' ? p.parameter : p;\n\n if (inner?.type === 'RestElement') {\n const argName: string = inner.argument?.name ?? 'unknown';\n const name = `...${argName}`;\n const typeAnn = inner.typeAnnotation;\n const type = typeAnn ? typeText(typeAnn) : undefined;\n const param: Parameter = { name, isOptional: false };\n if (type) param.type = type;\n return param;\n }\n\n if (inner?.type === 'AssignmentPattern') {\n const left = inner.left;\n const right = inner.right;\n const name: string = left?.name ?? 'unknown';\n const typeAnn = left?.typeAnnotation;\n const type = typeAnn ? typeText(typeAnn) : undefined;\n const defaultValue: string = sourceText.slice(right!.start, right!.end);\n const decos = extractDecorators(left?.decorators ?? []);\n const param: Parameter = { name, isOptional: true, defaultValue };\n if (type) param.type = type;\n if (decos.length > 0) param.decorators = decos;\n return param;\n }\n\n const name: string = inner?.name ?? inner?.pattern?.name ?? 'unknown';\n const optional: boolean = !!(inner?.optional);\n const typeAnn = inner?.typeAnnotation;\n const type = typeAnn ? typeText(typeAnn) : undefined;\n const decos = extractDecorators(inner?.decorators ?? []);\n const param: Parameter = { name, isOptional: optional };\n if (type) param.type = type;\n if (decos.length > 0) param.decorators = decos;\n return param;\n }\n\n function extractModifiers(node: OxcModNode, fn?: OxcModNode): Modifier[] {\n const mods: Modifier[] = [];\n if (fn?.async) mods.push('async');\n if (node.static) mods.push('static');\n if (node.abstract) mods.push('abstract');\n if (node.readonly) mods.push('readonly');\n if (node.override) mods.push('override');\n if (node.declare) mods.push('declare');\n if (node.const) mods.push('const');\n const acc = node.accessibility;\n if (acc === 'private') mods.push('private');\n else if (acc === 'protected') mods.push('protected');\n else if (acc === 'public') mods.push('public');\n return mods;\n }\n\n function classHeritage(node: OxcNode): Heritage[] {\n const heritage: Heritage[] = [];\n if (node.superClass) {\n const name = sourceText.slice(node.superClass.start, node.superClass.end);\n heritage.push({ kind: 'extends', name });\n }\n const impls = node.implements ?? [];\n for (const impl of impls) {\n const expr = impl.expression ?? impl;\n const name = sourceText.slice(expr.start, expr.end);\n heritage.push({ kind: 'implements', name });\n }\n return heritage;\n }\n\n function interfaceHeritage(node: OxcNode): Heritage[] {\n const heritage: Heritage[] = [];\n for (const ext of (node.extends ?? [])) {\n const expr = ext.expression ?? ext;\n const name = sourceText.slice(expr.start, expr.end);\n heritage.push({ kind: 'extends', name });\n }\n return heritage;\n }\n\n function extractClassMembers(bodyNodes: OxcMember[]): ExtractedSymbol[] {\n const members: ExtractedSymbol[] = [];\n for (const m of bodyNodes) {\n if (m.type === 'MethodDefinition') {\n const name: string = m.key?.name ?? 'unknown';\n const fnValue = m.value;\n const rawKind: string = m.kind ?? 'method';\n const methodKind =\n rawKind === 'constructor'\n ? 'constructor'\n : rawKind === 'get'\n ? 'getter'\n : rawKind === 'set'\n ? 'setter'\n : 'method';\n const mods = extractModifiers(m, fnValue);\n const params = (fnValue?.params ?? []).map(extractParam);\n const returnType = typeText(fnValue?.returnType);\n const s: ExtractedSymbol = {\n kind: 'method',\n name,\n span: span(m.start, m.end),\n isExported: false,\n methodKind,\n modifiers: mods,\n parameters: params.length > 0 ? params : undefined,\n returnType,\n };\n members.push(s);\n } else if (m.type === 'PropertyDefinition') {\n const name: string = m.key?.name ?? 'unknown';\n const mods = extractModifiers(m);\n const s: ExtractedSymbol = {\n kind: 'property',\n name,\n span: span(m.start, m.end),\n isExported: false,\n modifiers: mods,\n };\n members.push(s);\n }\n }\n return members;\n }\n\n function extractInterfaceMembers(bodyNodes: OxcMember[]): ExtractedSymbol[] {\n const members: ExtractedSymbol[] = [];\n for (const m of bodyNodes) {\n if (m.type === 'TSMethodSignature') {\n const name: string = m.key?.name ?? 'unknown';\n const params = (m.params ?? []).map(extractParam);\n const returnType = typeText(m.returnType);\n members.push({\n kind: 'method',\n name,\n span: span(m.start, m.end),\n isExported: false,\n modifiers: [],\n methodKind: 'method',\n parameters: params.length > 0 ? params : undefined,\n returnType,\n });\n } else if (m.type === 'TSPropertySignature') {\n const name: string = m.key?.name ?? 'unknown';\n const typeAnn = typeText(m.typeAnnotation);\n const s: ExtractedSymbol = {\n kind: 'property',\n name,\n span: span(m.start, m.end),\n isExported: false,\n modifiers: m.readonly ? ['readonly'] : [],\n returnType: typeAnn,\n };\n members.push(s);\n }\n }\n return members;\n }\n\n function buildSymbol(node: OxcNode, isExported: boolean): ExtractedSymbol | ExtractedSymbol[] | null {\n const type: string = node.type ?? '';\n\n if (type === 'FunctionDeclaration') {\n const name: string = node.id?.name ?? 'default';\n const params = (node.params ?? []).map(extractParam);\n const returnType = typeText(node.returnType);\n const mods = extractModifiers(node, node);\n const decos = extractDecorators(node.decorators ?? []);\n const typeParameters: string[] | undefined =\n node.typeParameters?.params?.map((p: { name?: { name?: string } }) => p.name?.name as string).filter(Boolean) || undefined;\n const sym: ExtractedSymbol = {\n kind: 'function',\n name,\n span: span(node.start, node.end),\n isExported,\n modifiers: mods,\n parameters: params.length > 0 ? params : undefined,\n returnType,\n decorators: decos.length > 0 ? decos : undefined,\n };\n if (typeParameters && typeParameters.length > 0) sym.typeParameters = typeParameters;\n return sym;\n }\n\n if (type === 'ClassDeclaration' || type === 'ClassExpression') {\n const name: string = node.id?.name ?? 'default';\n const heritage = classHeritage(node);\n const members = extractClassMembers(node.body?.body ?? []);\n const decos = extractDecorators(node.decorators ?? []);\n const mods = extractModifiers(node, node);\n const typeParameters: string[] | undefined =\n node.typeParameters?.params?.map((p: { name?: { name?: string } }) => p.name?.name as string).filter(Boolean) || undefined;\n const sym: ExtractedSymbol = {\n kind: 'class',\n name,\n span: span(node.start, node.end),\n isExported,\n modifiers: mods,\n heritage: heritage.length > 0 ? heritage : undefined,\n members: members.length > 0 ? members : undefined,\n decorators: decos.length > 0 ? decos : undefined,\n };\n if (typeParameters && typeParameters.length > 0) sym.typeParameters = typeParameters;\n return sym;\n }\n\n if (type === 'VariableDeclaration') {\n const symbols: ExtractedSymbol[] = [];\n for (const decl of node.declarations ?? []) {\n const id = decl.id;\n const init = decl.init;\n\n if (id?.type === 'ObjectPattern') {\n for (const prop of id.properties ?? []) {\n const propName: string = prop.value?.name ?? prop.key?.name ?? 'unknown';\n symbols.push({\n kind: 'variable' as SymbolKind,\n name: propName,\n span: span(prop.start ?? decl.start, prop.end ?? decl.end),\n isExported,\n modifiers: [],\n });\n }\n continue;\n }\n\n if (id?.type === 'ArrayPattern') {\n for (const elem of id.elements ?? []) {\n if (!elem || elem.type !== 'Identifier') continue;\n const elemName: string = elem.name ?? 'unknown';\n symbols.push({\n kind: 'variable' as SymbolKind,\n name: elemName,\n span: span(elem.start ?? decl.start, elem.end ?? decl.end),\n isExported,\n modifiers: [],\n });\n }\n continue;\n }\n\n const name: string = id?.name ?? 'unknown';\n let kind: SymbolKind = 'variable';\n let params: Parameter[] | undefined;\n let returnType: string | undefined;\n\n if (\n init?.type === 'FunctionExpression' ||\n init?.type === 'ArrowFunctionExpression'\n ) {\n kind = 'function';\n const rawParams = init.params ?? [];\n params = rawParams.map(extractParam);\n returnType = typeText(init.returnType);\n }\n const mods: Modifier[] = [];\n symbols.push({\n kind,\n name,\n span: span(decl.start, decl.end),\n isExported,\n modifiers: mods,\n parameters: params,\n returnType,\n });\n }\n if (symbols.length === 0) return null;\n if (symbols.length === 1) return symbols[0]!;\n return symbols;\n }\n\n if (type === 'TSTypeAliasDeclaration') {\n const name: string = node.id?.name ?? 'unknown';\n return {\n kind: 'type',\n name,\n span: span(node.start, node.end),\n isExported,\n modifiers: [],\n };\n }\n\n if (type === 'TSInterfaceDeclaration') {\n const name: string = node.id?.name ?? 'unknown';\n const heritage = interfaceHeritage(node);\n const members = extractInterfaceMembers(node.body?.body ?? []);\n const typeParameters: string[] | undefined =\n node.typeParameters?.params?.map((p: { name?: { name?: string } }) => p.name?.name as string).filter(Boolean) || undefined;\n const sym: ExtractedSymbol = {\n kind: 'interface',\n name,\n span: span(node.start, node.end),\n isExported,\n modifiers: [],\n heritage: heritage.length > 0 ? heritage : undefined,\n members: members.length > 0 ? members : undefined,\n };\n if (typeParameters && typeParameters.length > 0) sym.typeParameters = typeParameters;\n return sym;\n }\n\n if (type === 'TSEnumDeclaration') {\n const name: string = node.id?.name ?? 'unknown';\n const mods = extractModifiers(node);\n const rawMembers: Array<OxcSpan & { id?: { name?: string; value?: string } }> = node.body?.members ?? [];\n const members: ExtractedSymbol[] = rawMembers.map((m) => ({\n kind: 'property' as SymbolKind,\n name: m.id?.name ?? m.id?.value ?? 'unknown',\n span: span(m.start, m.end),\n isExported: false,\n modifiers: [],\n }));\n return {\n kind: 'enum',\n name,\n span: span(node.start, node.end),\n isExported,\n modifiers: mods,\n members: members.length > 0 ? members : undefined,\n };\n }\n\n return null;\n }\n\n const result: ExtractedSymbol[] = [];\n\n for (const node of program.body) {\n let sym: ExtractedSymbol | ExtractedSymbol[] | null = null;\n const record = node as unknown as Record<string, unknown>;\n const type: string = typeof record.type === 'string' ? record.type : '';\n\n if (type === 'ExportNamedDeclaration') {\n const n = node as unknown as {\n declaration?: unknown;\n start: number;\n end: number;\n };\n if (n.declaration) {\n sym = buildSymbol(n.declaration as OxcNode, true);\n if (sym && !Array.isArray(sym)) {\n sym.span = span(n.start, n.end);\n } else if (Array.isArray(sym)) {\n for (const s of sym) s.span = span(n.start, n.end);\n }\n }\n } else if (type === 'ExportDefaultDeclaration') {\n const n = node as unknown as {\n declaration?: { id?: { name?: string } } & Record<string, unknown>;\n start: number;\n end: number;\n };\n const decl = n.declaration;\n if (decl) {\n sym = buildSymbol(decl as unknown as OxcNode, true);\n if (sym && !Array.isArray(sym)) {\n sym.name = decl.id?.name ?? 'default';\n sym.isExported = true;\n sym.span = span(n.start, n.end);\n }\n }\n } else {\n sym = buildSymbol(node as unknown as OxcNode, false);\n }\n\n const syms: ExtractedSymbol[] = Array.isArray(sym) ? sym : sym ? [sym] : [];\n for (const s of syms) {\n const nodeStart = (node as { start?: number }).start ?? 0;\n const jsdocText = findJsDocComment(nodeStart);\n if (jsdocText) {\n const jsDocResult = parseJsDoc(jsdocText);\n if (!isErr(jsDocResult)) s.jsDoc = jsDocResult;\n }\n result.push(s);\n }\n }\n\n return result;\n}\n",
|
|
25
|
-
"import type { ParsedFile } from '../parser/types';\nimport type { ExtractedSymbol } from '../extractor/types';\nimport { extractSymbols } from '../extractor/symbol-extractor';\nimport { hashString } from '../common/hasher';\n\nexport interface SymbolDbRow {\n project: string;\n filePath: string;\n kind: string;\n name: string;\n startLine: number;\n startColumn: number;\n endLine: number;\n endColumn: number;\n isExported: number;\n signature: string | null;\n fingerprint: string | null;\n detailJson: string | null;\n contentHash: string;\n indexedAt: string;\n}\n\ninterface SymbolRepoPart {\n replaceFileSymbols(\n project: string,\n filePath: string,\n contentHash: string,\n symbols: SymbolDbRow[],\n ): void;\n}\n\nexport interface IndexFileSymbolsOptions {\n parsed: ParsedFile;\n project: string;\n filePath: string;\n contentHash: string;\n symbolRepo: SymbolRepoPart;\n}\n\nfunction buildSignature(sym: ExtractedSymbol): string | null {\n if (sym.kind === 'function' || sym.kind === 'method') {\n const paramCount = sym.parameters?.length ?? 0;\n const isAsync = sym.modifiers.includes('async') ? 1 : 0;\n return `params:${paramCount}|async:${isAsync}`;\n }\n return null;\n}\n\nfunction buildDetailJson(sym: ExtractedSymbol): string | null {\n const detail: Record<string, unknown> = {};\n\n if (sym.jsDoc) detail.jsDoc = sym.jsDoc;\n\n if (sym.kind === 'function' || sym.kind === 'method') {\n if (sym.parameters !== undefined) detail.parameters = sym.parameters;\n if (sym.returnType !== undefined) detail.returnType = sym.returnType;\n }\n\n if (sym.heritage?.length) detail.heritage = sym.heritage;\n if (sym.decorators?.length) detail.decorators = sym.decorators;\n if (sym.typeParameters?.length) detail.typeParameters = sym.typeParameters;\n if (sym.modifiers?.length) detail.modifiers = sym.modifiers;\n if (sym.members?.length) {\n detail.members = sym.members.map((m) => {\n const visibility = m.modifiers.find(\n (mod: string) => mod === 'private' || mod === 'protected' || mod === 'public',\n );\n return {\n name: m.name,\n kind: m.methodKind ?? m.kind,\n type: m.returnType,\n visibility,\n isStatic: m.modifiers.includes('static') || undefined,\n isReadonly: m.modifiers.includes('readonly') || undefined,\n };\n });\n }\n\n return Object.keys(detail).length > 0 ? JSON.stringify(detail) : null;\n}\n\nfunction buildRow(\n sym: ExtractedSymbol,\n name: string,\n project: string,\n filePath: string,\n contentHash: string,\n): SymbolDbRow {\n const signature = buildSignature(sym);\n const fingerprint = hashString(`${name}|${sym.kind}|${signature ?? ''}`);\n\n return {\n project,\n filePath,\n kind: sym.kind,\n name,\n startLine: sym.span.start.line,\n startColumn: sym.span.start.column,\n endLine: sym.span.end.line,\n endColumn: sym.span.end.column,\n isExported: sym.isExported ? 1 : 0,\n signature,\n fingerprint,\n detailJson: buildDetailJson(sym),\n contentHash,\n indexedAt: new Date().toISOString(),\n };\n}\n\nexport function indexFileSymbols(opts: IndexFileSymbolsOptions): void {\n const { parsed, project, filePath, contentHash, symbolRepo } = opts;\n\n const extracted = extractSymbols(parsed);\n const rows: SymbolDbRow[] = [];\n\n for (const sym of extracted) {\n rows.push(buildRow(sym, sym.name, project, filePath, contentHash));\n\n for (const member of sym.members ?? []) {\n rows.push(buildRow(member, `${sym.name}.${member.name}`, project, filePath, contentHash));\n }\n }\n\n symbolRepo.replaceFileSymbols(project, filePath, contentHash, rows);\n}\n",
|
|
26
|
-
"import { resolve, dirname, extname } from 'node:path';\nimport type { Program } from 'oxc-parser';\nimport type { TsconfigPaths } from '../common/tsconfig-resolver';\nimport type { ImportReference } from './types';\n\nexport function resolveImport(\n currentFilePath: string,\n importPath: string,\n tsconfigPaths?: TsconfigPaths,\n): string[] {\n const withTypeScriptCandidates = (resolved: string): string[] => {\n const extension = extname(resolved);\n if (extension === '') {\n return [\n resolved + '.ts',\n resolved + '.d.ts',\n resolved + '/index.ts',\n resolved + '/index.d.ts',\n resolved + '.mts',\n resolved + '/index.mts',\n resolved + '.cts',\n resolved + '/index.cts',\n ];\n }\n if (extension === '.js') return [resolved.slice(0, -3) + '.ts'];\n if (extension === '.mjs') return [resolved.slice(0, -4) + '.mts'];\n if (extension === '.cjs') return [resolved.slice(0, -4) + '.cts'];\n return [resolved];\n };\n\n if (importPath.startsWith('.')) {\n const resolved = resolve(dirname(currentFilePath), importPath);\n return withTypeScriptCandidates(resolved);\n }\n\n if (tsconfigPaths) {\n for (const [pattern, targets] of tsconfigPaths.paths) {\n if (targets.length === 0) continue;\n\n const starIdx = pattern.indexOf('*');\n\n if (starIdx === -1) {\n if (importPath === pattern) {\n const candidates: string[] = [];\n for (const t of targets) {\n candidates.push(...withTypeScriptCandidates(resolve(tsconfigPaths.baseUrl, t)));\n }\n return candidates;\n }\n } else {\n const prefix = pattern.slice(0, starIdx);\n const suffix = pattern.slice(starIdx + 1);\n if (\n importPath.startsWith(prefix) &&\n (suffix === '' || importPath.endsWith(suffix))\n ) {\n const captured = importPath.slice(\n prefix.length,\n suffix === '' ? undefined : importPath.length - suffix.length,\n );\n const candidates: string[] = [];\n for (const t of targets) {\n candidates.push(...withTypeScriptCandidates(resolve(tsconfigPaths.baseUrl, t.replace('*', captured))));\n }\n return candidates;\n }\n }\n }\n }\n\n return [];\n}\n\nexport function buildImportMap(\n ast: Program,\n currentFilePath: string,\n tsconfigPaths?: TsconfigPaths,\n resolveImportFn: (\n currentFilePath: string,\n importPath: string,\n tsconfigPaths?: TsconfigPaths,\n ) => string[] = resolveImport,\n): Map<string, ImportReference> {\n const map = new Map<string, ImportReference>();\n const body = (ast as unknown as { body?: Array<Record<string, unknown>> }).body ?? [];\n\n for (const node of body) {\n if (node.type !== 'ImportDeclaration') continue;\n\n const sourcePath: string = ((node.source as { value?: string } | undefined)?.value) ?? '';\n const candidates = resolveImportFn(currentFilePath, sourcePath, tsconfigPaths);\n if (candidates.length === 0) continue;\n const resolved = candidates[0];\n\n const specifiers = (node.specifiers as Array<Record<string, unknown>> | undefined) ?? [];\n for (const spec of specifiers) {\n switch (spec.type) {\n case 'ImportSpecifier':\n map.set((spec.local as { name: string }).name, {\n path: resolved!,\n importedName: (spec.imported as { name: string }).name,\n });\n break;\n case 'ImportDefaultSpecifier':\n map.set((spec.local as { name: string }).name, {\n path: resolved!,\n importedName: 'default',\n });\n break;\n case 'ImportNamespaceSpecifier':\n map.set((spec.local as { name: string }).name, {\n path: resolved!,\n importedName: '*',\n });\n break;\n }\n }\n }\n\n return map;\n}\n",
|
|
27
|
-
"import type { QualifiedName } from '../extractor/types';\n\nconst SKIP_KEYS = new Set(['loc', 'start', 'end', 'scope']);\n\nexport function isNode(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\nexport function isNodeArray(value: unknown): value is ReadonlyArray<unknown> {\n return Array.isArray(value);\n}\n\nexport function visit(\n node: unknown,\n callback: (node: Record<string, unknown>) => void,\n): void {\n if (!node || typeof node !== 'object') return;\n\n if (Array.isArray(node)) {\n for (const item of node) visit(item, callback);\n return;\n }\n\n const record = node as Record<string, unknown>;\n callback(record);\n\n for (const key of Object.keys(record)) {\n if (SKIP_KEYS.has(key)) continue;\n const child = record[key];\n if (child && typeof child === 'object') {\n visit(child, callback);\n }\n }\n}\n\nexport function collectNodes(\n root: unknown,\n predicate: (node: Record<string, unknown>) => boolean,\n): Record<string, unknown>[] {\n const results: Record<string, unknown>[] = [];\n visit(root, (node) => {\n if (predicate(node)) results.push(node);\n });\n return results;\n}\n\nexport function getNodeHeader(\n node: Record<string, unknown>,\n parent?: Record<string, unknown> | null,\n): string {\n const id = node.id as Record<string, unknown> | undefined;\n if (id && typeof id.name === 'string') return id.name;\n\n const key = node.key as Record<string, unknown> | undefined;\n if (key) {\n if (typeof key.name === 'string') return key.name;\n if (\n (key.type === 'StringLiteral' || key.type === 'Literal') &&\n typeof key.value === 'string'\n ) {\n return key.value;\n }\n }\n\n if (parent) {\n if (parent.type === 'VariableDeclarator') {\n const pid = parent.id as Record<string, unknown> | undefined;\n if (pid && typeof pid.name === 'string') return pid.name;\n }\n if (\n parent.type === 'MethodDefinition' ||\n parent.type === 'PropertyDefinition' ||\n parent.type === 'Property'\n ) {\n const pkey = parent.key as Record<string, unknown> | undefined;\n if (pkey) {\n if (typeof pkey.name === 'string') return pkey.name;\n if (typeof pkey.value === 'string') return pkey.value;\n }\n }\n }\n\n return 'anonymous';\n}\n\nexport function isFunctionNode(node: Record<string, unknown>): boolean {\n return (\n node.type === 'FunctionDeclaration' ||\n node.type === 'FunctionExpression' ||\n node.type === 'ArrowFunctionExpression'\n );\n}\n\nexport function getNodeName(node: unknown): string | null {\n if (!node || typeof node !== 'object' || Array.isArray(node)) return null;\n const record = node as Record<string, unknown>;\n return typeof record.name === 'string' ? record.name : null;\n}\n\nexport function getStringLiteralValue(node: unknown): string | null {\n if (!node || typeof node !== 'object' || Array.isArray(node)) return null;\n const record = node as Record<string, unknown>;\n if (\n (record.type === 'StringLiteral' || record.type === 'Literal') &&\n typeof record.value === 'string'\n ) {\n return record.value;\n }\n return null;\n}\n\nexport function getQualifiedName(expr: unknown): QualifiedName | null {\n if (!expr || typeof expr !== 'object' || Array.isArray(expr)) return null;\n const node = expr as Record<string, unknown>;\n\n if (node.type === 'Identifier') {\n const name = node.name as string;\n return { root: name, parts: [], full: name };\n }\n\n if (node.type === 'ThisExpression') {\n return { root: 'this', parts: [], full: 'this' };\n }\n\n if (node.type === 'Super') {\n return { root: 'super', parts: [], full: 'super' };\n }\n\n if (node.type === 'MemberExpression') {\n const parts: string[] = [];\n let current: Record<string, unknown> = node;\n\n while (current.type === 'MemberExpression') {\n const prop = current.property as Record<string, unknown> | undefined;\n if (!prop || typeof prop.name !== 'string') return null;\n parts.unshift(prop.name);\n current = current.object as Record<string, unknown>;\n }\n\n let root: string;\n if (current.type === 'Identifier') {\n root = current.name as string;\n } else if (current.type === 'ThisExpression') {\n root = 'this';\n } else if (current.type === 'Super') {\n root = 'super';\n } else {\n return null;\n }\n\n const full = [root, ...parts].join('.');\n return { root, parts, full };\n }\n\n return null;\n}\n",
|
|
28
|
-
"import type { Program } from 'oxc-parser';\nimport type { TsconfigPaths } from '../common/tsconfig-resolver';\nimport type { CodeRelation } from './types';\nimport { resolveImport } from './extractor-utils';\nimport { visit, getStringLiteralValue } from '../parser/ast-utils';\n\nexport function extractImports(\n ast: Program,\n filePath: string,\n tsconfigPaths?: TsconfigPaths,\n resolveImportFn: (\n currentFilePath: string,\n importPath: string,\n tsconfigPaths?: TsconfigPaths,\n ) => string[] = resolveImport,\n): CodeRelation[] {\n const relations: CodeRelation[] = [];\n const body = (ast as unknown as { body?: Array<Record<string, unknown>> }).body ?? [];\n\n for (const node of body) {\n if (node.type === 'ImportDeclaration') {\n const sourcePath: string = ((node.source as { value?: string } | undefined)?.value) ?? '';\n const candidates = resolveImportFn(filePath, sourcePath, tsconfigPaths);\n if (candidates.length === 0) continue;\n const resolved = candidates[0]!;\n\n const isType = node.importKind === 'type';\n const specifiers = (node.specifiers as Array<Record<string, unknown>> | undefined) ?? [];\n\n if (specifiers.length === 0) {\n // side-effect import: import './foo'\n const meta: Record<string, unknown> = {};\n if (isType) meta.isType = true;\n relations.push({\n type: isType ? 'type-references' : 'imports',\n srcFilePath: filePath,\n srcSymbolName: null,\n dstFilePath: resolved,\n dstSymbolName: null,\n ...(Object.keys(meta).length > 0 ? { metaJson: JSON.stringify(meta) } : {}),\n });\n } else {\n for (const spec of specifiers) {\n const specType = spec.type as string;\n const isSpecType = isType || (spec.importKind as string) === 'type';\n const meta: Record<string, unknown> = {};\n if (isSpecType) meta.isType = true;\n\n let dstSymbolName: string;\n let srcSymbolName: string;\n\n if (specType === 'ImportDefaultSpecifier') {\n dstSymbolName = 'default';\n srcSymbolName = (spec.local as { name: string }).name;\n } else if (specType === 'ImportNamespaceSpecifier') {\n dstSymbolName = '*';\n srcSymbolName = (spec.local as { name: string }).name;\n meta.importKind = 'namespace';\n } else {\n // ImportSpecifier\n dstSymbolName = (spec.imported as { name: string }).name;\n srcSymbolName = (spec.local as { name: string }).name;\n }\n\n relations.push({\n type: isSpecType ? 'type-references' : 'imports',\n srcFilePath: filePath,\n srcSymbolName,\n dstFilePath: resolved,\n dstSymbolName,\n ...(Object.keys(meta).length > 0 ? { metaJson: JSON.stringify(meta) } : {}),\n });\n }\n }\n continue;\n }\n\n if (node.type === 'ExportAllDeclaration' && node.source) {\n const sourcePath: string = ((node.source as { value?: string } | undefined)?.value) ?? '';\n const candidates = resolveImportFn(filePath, sourcePath, tsconfigPaths);\n if (candidates.length === 0) continue;\n const resolved = candidates[0]!;\n\n const isType = node.exportKind === 'type';\n const meta: Record<string, unknown> = { isReExport: true };\n if (isType) meta.isType = true;\n relations.push({\n type: isType ? 'type-references' : 're-exports',\n srcFilePath: filePath,\n srcSymbolName: null,\n dstFilePath: resolved,\n dstSymbolName: null,\n metaJson: JSON.stringify(meta),\n });\n continue;\n }\n\n if (node.type === 'ExportNamedDeclaration' && node.source) {\n const sourcePath: string = ((node.source as { value?: string } | undefined)?.value) ?? '';\n const candidates = resolveImportFn(filePath, sourcePath, tsconfigPaths);\n if (candidates.length === 0) continue;\n const resolved = candidates[0]!;\n\n const isType = node.exportKind === 'type';\n const specifierNodes = (node.specifiers as Array<Record<string, unknown>> | undefined) ?? [];\n const specifiers = specifierNodes.map((s) => ({\n local: (s.local as { name: string }).name,\n exported: (s.exported as { name: string }).name,\n }));\n\n const meta: Record<string, unknown> = { isReExport: true, specifiers };\n if (isType) meta.isType = true;\n\n relations.push({\n type: isType ? 'type-references' : 're-exports',\n srcFilePath: filePath,\n srcSymbolName: null,\n dstFilePath: resolved,\n dstSymbolName: null,\n metaJson: JSON.stringify(meta),\n });\n }\n }\n\n visit(ast, (node) => {\n if (node.type !== 'ImportExpression') return;\n const sourceValue = getStringLiteralValue(node.source);\n if (!sourceValue) return;\n const candidates = resolveImportFn(filePath, sourceValue, tsconfigPaths);\n if (candidates.length === 0) return;\n const resolved = candidates[0]!;\n\n relations.push({\n type: 'imports',\n srcFilePath: filePath,\n srcSymbolName: null,\n dstFilePath: resolved,\n dstSymbolName: null,\n metaJson: JSON.stringify({ isDynamic: true }),\n });\n });\n\n return relations;\n}\n",
|
|
29
|
-
"import type { Program } from 'oxc-parser';\nimport type { ImportReference, CodeRelation } from './types';\nimport { getQualifiedName } from '../parser/ast-utils';\n\nexport function extractCalls(\n ast: Program,\n filePath: string,\n importMap: Map<string, ImportReference>,\n): CodeRelation[] {\n const relations: CodeRelation[] = [];\n const functionStack: string[] = [];\n const classStack: string[] = [];\n\n function currentCaller(): string | null {\n if (functionStack.length > 0) return functionStack[functionStack.length - 1] ?? null;\n return null;\n }\n\n function resolveCallee(\n qn: { root: string; parts: string[]; full: string } | null,\n ): { dstFilePath: string; dstSymbolName: string; resolution: string } | null {\n if (!qn) return null;\n\n const ref = importMap.get(qn.root);\n\n if (qn.parts.length === 0) {\n if (ref) {\n return { dstFilePath: ref.path, dstSymbolName: ref.importedName, resolution: 'import' };\n }\n return { dstFilePath: filePath, dstSymbolName: qn.root, resolution: 'local' };\n } else {\n if (ref && ref.importedName === '*') {\n const dstSymbolName = qn.parts[qn.parts.length - 1]!;\n return { dstFilePath: ref.path, dstSymbolName, resolution: 'namespace' };\n }\n return { dstFilePath: filePath, dstSymbolName: qn.full, resolution: 'local-member' };\n }\n }\n\n function walk(node: unknown): void {\n if (!node || typeof node !== 'object') return;\n\n if (Array.isArray(node)) {\n for (const item of node) walk(item);\n return;\n }\n\n const record = node as Record<string, unknown>;\n const type: string = typeof record.type === 'string' ? record.type : '';\n\n if (type === 'ClassDeclaration' || type === 'ClassExpression') {\n const classNode = record as { id?: { name?: string }; body?: unknown };\n const className: string = classNode.id?.name ?? 'AnonymousClass';\n classStack.push(className);\n walk(classNode.body);\n classStack.pop();\n return;\n }\n\n if (type === 'FunctionDeclaration') {\n const functionNode = record as { id?: { name?: string }; body?: unknown };\n const name: string = functionNode.id?.name ?? 'anonymous';\n functionStack.push(name);\n walk(functionNode.body);\n functionStack.pop();\n return;\n }\n\n if (type === 'VariableDeclarator' && (record as { init?: { type?: string } }).init && (\n (record as { init?: { type?: string } }).init?.type === 'FunctionExpression' ||\n (record as { init?: { type?: string } }).init?.type === 'ArrowFunctionExpression'\n )) {\n const declarator = record as { id?: { name?: string }; init?: { body?: unknown } };\n const name: string = declarator.id?.name ?? 'anonymous';\n functionStack.push(name);\n walk(declarator.init?.body ?? declarator.init);\n functionStack.pop();\n return;\n }\n\n if (type === 'MethodDefinition' && (record as { value?: unknown }).value) {\n const method = record as { key?: { name?: string }; value?: { body?: unknown } };\n const className = classStack[classStack.length - 1] ?? '';\n const methodName: string = method.key?.name ?? 'anonymous';\n const fullName = className ? `${className}.${methodName}` : methodName;\n functionStack.push(fullName);\n walk(method.value?.body);\n functionStack.pop();\n return;\n }\n\n if (type === 'FunctionExpression' || type === 'ArrowFunctionExpression') {\n const parentCaller = currentCaller();\n const anonymousName = parentCaller ? `${parentCaller}.<anonymous>` : '<anonymous>';\n functionStack.push(anonymousName);\n walk((record as { body?: unknown }).body);\n functionStack.pop();\n return;\n }\n\n if (type === 'CallExpression') {\n const call = record as { callee?: unknown; arguments?: unknown[] };\n const qn = getQualifiedName(call.callee);\n const dst = resolveCallee(qn);\n if (dst) {\n const srcSymbolName = currentCaller();\n const meta: Record<string, unknown> = {};\n if (srcSymbolName === null) meta.scope = 'module';\n\n relations.push({\n type: 'calls',\n srcFilePath: filePath,\n srcSymbolName,\n dstFilePath: dst.dstFilePath,\n dstSymbolName: dst.dstSymbolName,\n ...(Object.keys(meta).length > 0 ? { metaJson: JSON.stringify(meta) } : {}),\n });\n }\n walk(call.callee);\n for (const arg of call.arguments ?? []) walk(arg);\n return;\n }\n\n if (type === 'NewExpression') {\n const ctorCall = record as { callee?: unknown; arguments?: unknown[] };\n const qn = getQualifiedName(ctorCall.callee);\n const dst = resolveCallee(qn);\n if (dst) {\n const srcSymbolName = currentCaller();\n const meta: Record<string, unknown> = { isNew: true };\n if (srcSymbolName === null) meta.scope = 'module';\n\n relations.push({\n type: 'calls',\n srcFilePath: filePath,\n srcSymbolName,\n dstFilePath: dst.dstFilePath,\n dstSymbolName: dst.dstSymbolName,\n metaJson: JSON.stringify(meta),\n });\n }\n for (const arg of ctorCall.arguments ?? []) walk(arg);\n return;\n }\n\n for (const key of Object.keys(record)) {\n if (key === 'loc' || key === 'start' || key === 'end' || key === 'scope') continue;\n const child = record[key];\n if (child && typeof child === 'object') {\n walk(child);\n }\n }\n }\n\n walk(ast);\n return relations;\n}\n",
|
|
30
|
-
"import type { Program } from 'oxc-parser';\nimport type { ImportReference, CodeRelation } from './types';\nimport { visit, getQualifiedName } from '../parser/ast-utils';\n\nexport function extractHeritage(\n ast: Program,\n filePath: string,\n importMap: Map<string, ImportReference>,\n): CodeRelation[] {\n const relations: CodeRelation[] = [];\n\n visit(ast, (node) => {\n if (node.type === 'TSInterfaceDeclaration') {\n const interfaceName: string = ((node.id as { name?: string } | undefined)?.name) ?? 'AnonymousInterface';\n const interfaces = (node.extends as unknown[] | undefined) ?? [];\n for (const item of interfaces) {\n const expr = (item as { expression?: unknown }).expression ?? item;\n const qn = getQualifiedName(expr);\n if (!qn) continue;\n const rel = resolveHeritageDst(qn, filePath, importMap);\n relations.push({\n type: 'extends',\n srcFilePath: filePath,\n srcSymbolName: interfaceName,\n ...rel,\n });\n }\n return;\n }\n\n if (node.type !== 'ClassDeclaration' && node.type !== 'ClassExpression') return;\n\n const className: string =\n ((node.id as { name?: string } | undefined)?.name) ?? 'AnonymousClass';\n\n if (node.superClass) {\n const qn = getQualifiedName(node.superClass);\n if (qn) {\n const rel = resolveHeritageDst(qn, filePath, importMap);\n relations.push({\n type: 'extends',\n srcFilePath: filePath,\n srcSymbolName: className,\n ...rel,\n });\n }\n }\n\n const impls = (node.implements as unknown[] | undefined) ?? [];\n for (const impl of impls) {\n const expr = (impl as { expression?: unknown }).expression ?? impl;\n const qn = getQualifiedName(expr);\n if (!qn) continue;\n const rel = resolveHeritageDst(qn, filePath, importMap);\n relations.push({\n type: 'implements',\n srcFilePath: filePath,\n srcSymbolName: className,\n ...rel,\n });\n }\n });\n\n return relations;\n}\n\nfunction resolveHeritageDst(\n qn: { root: string; parts: string[]; full: string },\n currentFilePath: string,\n importMap: Map<string, ImportReference>,\n): { dstFilePath: string; dstSymbolName: string; metaJson?: string } {\n const ref = importMap.get(qn.root);\n\n if (ref) {\n if (ref.importedName === '*') {\n const dstSymbolName = qn.parts[qn.parts.length - 1] ?? qn.root;\n return {\n dstFilePath: ref.path,\n dstSymbolName,\n metaJson: JSON.stringify({ isNamespaceImport: true }),\n };\n }\n return {\n dstFilePath: ref.path,\n dstSymbolName: qn.parts.length > 0 ? qn.full : ref.importedName,\n };\n }\n\n return {\n dstFilePath: currentFilePath,\n dstSymbolName: qn.full,\n metaJson: JSON.stringify({ isLocal: true }),\n };\n}\n",
|
|
31
|
-
"import type { Program } from 'oxc-parser';\nimport type { TsconfigPaths } from '../common/tsconfig-resolver';\nimport type { CodeRelation } from './types';\nimport { buildImportMap, resolveImport } from './extractor-utils';\nimport { extractImports } from './imports-extractor';\nimport { extractCalls } from './calls-extractor';\nimport { extractHeritage } from './heritage-extractor';\n\nexport type ResolveImportFn = (\n currentFilePath: string,\n importPath: string,\n tsconfigPaths?: TsconfigPaths,\n) => string[];\n\nexport function extractRelations(\n ast: Program,\n filePath: string,\n tsconfigPaths?: TsconfigPaths,\n resolveImportFn: ResolveImportFn = resolveImport,\n): CodeRelation[] {\n const importMap = buildImportMap(ast, filePath, tsconfigPaths, resolveImportFn);\n\n const imports = extractImports(ast, filePath, tsconfigPaths, resolveImportFn);\n const calls = extractCalls(ast, filePath, importMap);\n const heritage = extractHeritage(ast, filePath, importMap);\n\n return [...imports, ...calls, ...heritage];\n}\n",
|
|
32
|
-
"import type { Program } from 'oxc-parser';\nimport { extractRelations } from '../extractor/relation-extractor';\nimport { toAbsolutePath, toRelativePath } from '../common/path-utils';\nimport { resolveImport } from '../extractor/extractor-utils';\nimport { resolveFileProject } from '../common/project-discovery';\nimport type { ProjectBoundary } from '../common/project-discovery';\nimport type { TsconfigPaths } from '../common/tsconfig-resolver';\n\nexport interface RelationDbRow {\n project: string;\n type: string;\n srcFilePath: string;\n srcSymbolName: string | null;\n dstProject: string;\n dstFilePath: string;\n dstSymbolName: string | null;\n metaJson: string | null;\n}\n\ninterface RelationRepoPart {\n replaceFileRelations(\n project: string,\n filePath: string,\n relations: RelationDbRow[],\n ): void;\n}\n\nexport interface IndexFileRelationsOptions {\n ast: Program;\n project: string;\n filePath: string;\n relationRepo: RelationRepoPart;\n projectRoot: string;\n tsconfigPaths?: TsconfigPaths;\n /** 인덱싱된 파일 경로 Set. `${project}::${filePath}` 형식. */\n knownFiles?: Set<string>;\n /** 프로젝트 경계 목록 (dstProject 결정용) */\n boundaries?: ProjectBoundary[];\n}\n\nexport function indexFileRelations(opts: IndexFileRelationsOptions): number {\n const { ast, project, filePath, relationRepo, projectRoot, tsconfigPaths, knownFiles, boundaries } = opts;\n\n const absFilePath = toAbsolutePath(projectRoot, filePath);\n\n // knownFiles가 주어지면, 후보 중 knownFiles에 있는 경로를 선택하는 커스텀 resolver 조립\n const customResolver = knownFiles\n ? (currentFile: string, importPath: string, paths?: TsconfigPaths) => {\n // 기본 해석 (상대경로 + tsconfig paths)\n const candidates = resolveImport(currentFile, importPath, paths);\n\n // 후보 중 knownFiles에 있는 첫 번째 선택\n for (const c of candidates) {\n const rel = toRelativePath(projectRoot, c);\n // 모든 project에서 검색\n if (boundaries) {\n const p = resolveFileProject(rel, boundaries);\n if (knownFiles.has(`${p}::${rel}`)) return [c];\n } else {\n if (knownFiles.has(`${project}::${rel}`)) return [c];\n }\n }\n return []; // knownFiles에 없으면 빈 배열 → relation 미생성\n }\n : undefined;\n\n const rawRelations = extractRelations(ast, absFilePath, tsconfigPaths, customResolver);\n\n const rows: RelationDbRow[] = [];\n\n for (const rel of rawRelations) {\n const relDst = toRelativePath(projectRoot, rel.dstFilePath);\n\n if (relDst.startsWith('..')) continue;\n\n const relSrc = toRelativePath(projectRoot, rel.srcFilePath);\n\n // dstProject 결정: boundaries가 있으면 dstFilePath 기준으로 project 해석\n const dstProject = boundaries\n ? resolveFileProject(relDst, boundaries)\n : project;\n\n rows.push({\n project,\n type: rel.type,\n srcFilePath: relSrc,\n srcSymbolName: rel.srcSymbolName ?? null,\n dstProject,\n dstFilePath: relDst,\n dstSymbolName: rel.dstSymbolName ?? null,\n metaJson: rel.metaJson ?? null,\n });\n }\n\n relationRepo.replaceFileRelations(project, filePath, rows);\n return rows.length;\n}\n",
|
|
33
|
-
"import type { WatcherRole } from \"./types\";\n\ninterface WatcherOwnerRow {\n pid: number;\n heartbeat_at: string;\n instance_id: string | null;\n}\n\nexport interface WatcherOwnerStore {\n immediateTransaction<T>(fn: () => T): T;\n selectOwner(): WatcherOwnerRow | undefined;\n insertOwner(pid: number, instanceId?: string): void;\n replaceOwner(pid: number, instanceId?: string): void;\n touchOwner(pid: number): void;\n deleteOwner(pid: number): void;\n}\n\ninterface AcquireOptions {\n now?: () => number;\n isAlive?: (pid: number) => boolean;\n staleAfterSeconds?: number;\n instanceId?: string;\n}\n\nfunction defaultIsAlive(pid: number): boolean {\n try {\n process.kill(pid, 0);\n return true;\n } catch (error) {\n if (typeof error === \"object\" && error && \"code\" in error) {\n return (error as { code?: string }).code !== \"ESRCH\";\n }\n\n return true;\n }\n}\n\nfunction toEpochMs(value: string): number {\n const ms = new Date(value).getTime();\n return Number.isNaN(ms) ? 0 : ms;\n}\n\nexport function acquireWatcherRole(\n db: WatcherOwnerStore,\n pid: number,\n options: AcquireOptions = {},\n): WatcherRole {\n const now = options.now ?? Date.now;\n const isAlive = options.isAlive ?? defaultIsAlive;\n const staleAfterSeconds = options.staleAfterSeconds ?? 60;\n const instanceId = options.instanceId;\n\n return db.immediateTransaction(() => {\n const owner = db.selectOwner();\n if (!owner) {\n db.insertOwner(pid, instanceId);\n return \"owner\";\n }\n\n const heartbeatAgeSeconds = Math.floor((now() - toEpochMs(owner.heartbeat_at)) / 1000);\n const pidAlive = isAlive(owner.pid);\n\n // PID recycling check: if PID is alive but instance_id doesn't match,\n // the OS recycled the PID to an unrelated process\n if (pidAlive && instanceId && owner.instance_id && owner.instance_id !== instanceId && owner.pid !== pid) {\n db.replaceOwner(pid, instanceId);\n return \"owner\";\n }\n\n if (pidAlive && heartbeatAgeSeconds < staleAfterSeconds) {\n return \"reader\";\n }\n\n db.replaceOwner(pid, instanceId);\n return \"owner\";\n });\n}\n\nexport function releaseWatcherRole(db: WatcherOwnerStore, pid: number): void {\n db.deleteOwner(pid);\n}\n\nexport function updateHeartbeat(db: WatcherOwnerStore, pid: number): void {\n db.touchOwner(pid);\n}\n",
|
|
34
|
-
"export class LruCache<K, V> {\n #capacity: number;\n #map = new Map<K, V>();\n\n constructor(capacity: number) {\n this.#capacity = Math.max(1, capacity);\n }\n\n get size(): number {\n return this.#map.size;\n }\n\n has(key: K): boolean {\n return this.#map.has(key);\n }\n\n get(key: K): V | undefined {\n if (!this.#map.has(key)) {\n return undefined;\n }\n const value = this.#map.get(key)!;\n this.#map.delete(key);\n this.#map.set(key, value);\n return value;\n }\n\n set(key: K, value: V): void {\n if (this.#map.has(key)) {\n this.#map.delete(key);\n }\n\n this.#map.set(key, value);\n\n if (this.#map.size > this.#capacity) {\n const oldestKey = this.#map.keys().next().value as K | undefined;\n if (oldestKey !== undefined) {\n this.#map.delete(oldestKey);\n }\n }\n }\n\n delete(key: K): boolean {\n return this.#map.delete(key);\n }\n\n clear(): void {\n this.#map.clear();\n }\n}\n",
|
|
35
|
-
"import type { ParsedFile } from './types';\nimport { LruCache } from '../common/lru-cache';\n\nexport class ParseCache {\n private readonly lru: LruCache<string, ParsedFile>;\n\n constructor(capacity: number = 500) {\n this.lru = new LruCache<string, ParsedFile>(capacity);\n }\n\n get(filePath: string): ParsedFile | undefined {\n return this.lru.get(filePath);\n }\n\n set(filePath: string, parsed: ParsedFile): void {\n this.lru.set(filePath, parsed);\n }\n\n invalidate(filePath: string): void {\n this.lru.delete(filePath);\n }\n\n invalidateAll(): void {\n this.lru.clear();\n }\n\n size(): number {\n return this.lru.size;\n }\n}\n",
|
|
36
|
-
"import type { SymbolKind } from '../extractor/types';\nimport type { SymbolRecord } from '../store/repositories/symbol.repository';\nimport { toFtsPrefixQuery } from '../store/repositories/fts-utils';\n\n/**\n * Filters for {@link symbolSearch}.\n *\n * All fields are optional. Omitted fields impose no constraint.\n */\nexport interface SymbolSearchQuery {\n /** Full-text search on symbol names (prefix matching). */\n text?: string;\n /** Exact symbol name match. When `true`, `text` is treated as an exact name (not FTS prefix). */\n exact?: boolean;\n /** Restrict to a specific {@link SymbolKind}. */\n kind?: SymbolKind;\n /** Restrict to symbols declared in this file path. */\n filePath?: string;\n /** `true` for exported symbols only, `false` for non-exported only. */\n isExported?: boolean;\n /** Limit results to this project. Defaults to the primary project. */\n project?: string;\n /** Maximum number of results. Defaults to `100`. */\n limit?: number;\n /**\n * Filter by decorator name (LEG-1).\n * Restricts results to symbols annotated with this decorator (matched against `detailJson.decorators[].name`).\n */\n decorator?: string;\n /**\n * Filter by regex pattern applied to the symbol name (FR-19).\n * Requires the `REGEXP` SQL function to be registered in the DB connection.\n */\n regex?: string;\n /**\n * Filter by the resolved (inferred) type text.\n * Requires the semantic layer (`semantic: true`) to have populated this field.\n */\n resolvedType?: string;\n}\n\n/**\n * A single result returned by {@link symbolSearch}.\n */\nexport interface SymbolSearchResult {\n /** Database row id. */\n id: number;\n /** Absolute file path containing the symbol. */\n filePath: string;\n /** Kind of the symbol (function, class, variable, etc.). */\n kind: SymbolKind;\n /** Symbol name. */\n name: string;\n /** Source location span (start/end line and column). */\n span: { start: { line: number; column: number }; end: { line: number; column: number } };\n /** Whether the symbol is exported from its module. */\n isExported: boolean;\n /** Human-readable signature text, if available. */\n signature: string | null;\n /** Content-hash fingerprint for change detection. */\n fingerprint: string | null;\n /** Arbitrary detail fields stored as JSON. */\n detail: Record<string, unknown>;\n}\n\nexport interface ISymbolRepo {\n searchByQuery(opts: {\n ftsQuery?: string;\n exactName?: string;\n kind?: string;\n filePath?: string;\n isExported?: boolean;\n project?: string;\n limit: number;\n decorator?: string;\n regex?: string;\n resolvedType?: string;\n }): (SymbolRecord & { id: number })[];\n}\n\n/**\n * Search the symbol index using the given query filters.\n *\n * @param options - Symbol repository, default project, and search query.\n * @returns An array of {@link SymbolSearchResult} entries matching the query.\n */\nexport function symbolSearch(options: {\n symbolRepo: ISymbolRepo;\n project?: string;\n query: SymbolSearchQuery;\n}): SymbolSearchResult[] {\n const { symbolRepo, project, query } = options;\n const effectiveProject = query.project ?? project;\n const limit = query.limit ?? 100;\n\n const opts: Parameters<ISymbolRepo['searchByQuery']>[0] = {\n kind: query.kind,\n filePath: query.filePath,\n isExported: query.isExported,\n project: effectiveProject,\n limit,\n resolvedType: query.resolvedType,\n };\n\n if (query.text) {\n if (query.exact) {\n opts.exactName = query.text;\n } else {\n const ftsQuery = toFtsPrefixQuery(query.text);\n if (ftsQuery) opts.ftsQuery = ftsQuery;\n }\n }\n\n if (query.decorator) opts.decorator = query.decorator;\n if (query.regex) opts.regex = query.regex;\n\n const records = symbolRepo.searchByQuery(opts);\n\n return records.map(r => ({\n id: r.id,\n filePath: r.filePath,\n kind: r.kind as SymbolKind,\n name: r.name,\n span: {\n start: { line: r.startLine, column: r.startColumn },\n end: { line: r.endLine, column: r.endColumn },\n },\n isExported: r.isExported === 1,\n signature: r.signature,\n fingerprint: r.fingerprint,\n detail: r.detailJson ? (() => {\n try { return JSON.parse(r.detailJson!) as Record<string, unknown>; }\n catch { return {}; }\n })() : {},\n }));\n}\n",
|
|
37
|
-
"import type { CodeRelation } from '../extractor/types';\nimport type { RelationRecord } from '../store/repositories/relation.repository';\n\n/**\n * A {@link CodeRelation} enriched with the destination project identifier\n * as stored in the relation index.\n */\nexport interface StoredCodeRelation extends CodeRelation {\n dstProject: string;\n}\n\n/**\n * Filters for {@link relationSearch}.\n *\n * All fields are optional. Omitted fields impose no constraint.\n */\nexport interface RelationSearchQuery {\n /** Source file path. */\n srcFilePath?: string;\n /** Source symbol name. */\n srcSymbolName?: string;\n /** Destination file path. */\n dstFilePath?: string;\n /** Destination symbol name. */\n dstSymbolName?: string;\n /** Destination project. */\n dstProject?: string;\n /** Relationship type: `'imports'`, `'calls'`, `'extends'`, or `'implements'`. */\n type?: CodeRelation['type'];\n /** Limit results to this project. */\n project?: string;\n /** Maximum number of results. Defaults to `500`. */\n limit?: number;\n}\n\nexport interface IRelationRepo {\n searchRelations(opts: {\n srcFilePath?: string;\n srcSymbolName?: string;\n dstFilePath?: string;\n dstSymbolName?: string;\n dstProject?: string;\n type?: string;\n project?: string;\n limit: number;\n }): RelationRecord[];\n}\n\n/**\n * Search the relation index using the given query filters.\n *\n * @param options - Relation repository, default project, and search query.\n * @returns An array of {@link CodeRelation} entries matching the query.\n */\nexport function relationSearch(options: {\n relationRepo: IRelationRepo;\n project?: string;\n query: RelationSearchQuery;\n}): StoredCodeRelation[] {\n const { relationRepo, project, query } = options;\n const effectiveProject = query.project ?? project;\n const limit = query.limit ?? 500;\n\n const records = relationRepo.searchRelations({\n srcFilePath: query.srcFilePath,\n srcSymbolName: query.srcSymbolName,\n dstFilePath: query.dstFilePath,\n dstSymbolName: query.dstSymbolName,\n dstProject: query.dstProject,\n type: query.type,\n project: effectiveProject,\n limit,\n });\n\n return records.map(r => {\n let meta: Record<string, unknown> | undefined;\n if (r.metaJson) {\n try {\n meta = JSON.parse(r.metaJson) as Record<string, unknown>;\n } catch {\n // malformed JSON → meta stays undefined\n }\n }\n return {\n type: r.type as CodeRelation['type'],\n srcFilePath: r.srcFilePath,\n srcSymbolName: r.srcSymbolName,\n dstFilePath: r.dstFilePath,\n dstSymbolName: r.dstSymbolName,\n dstProject: r.dstProject,\n metaJson: r.metaJson ?? undefined,\n meta,\n };\n });\n}\n",
|
|
38
|
-
"import { findInFiles, Lang } from '@ast-grep/napi';\n\n/**\n * A single structural-pattern match found in a source file.\n */\nexport interface PatternMatch {\n /** Absolute path of the file containing the match. */\n filePath: string;\n /** 1-based start line number of the matched node. */\n startLine: number;\n /** 1-based end line number of the matched node. */\n endLine: number;\n /** Source text of the matched node. */\n matchedText: string;\n}\n\n/**\n * Options for {@link patternSearch}.\n */\nexport interface PatternSearchOptions {\n /** An ast-grep structural pattern string (e.g. `'console.log($$$)'`). */\n pattern: string;\n /** Absolute file paths (or directories) to search within. */\n filePaths: string[];\n}\n\n/**\n * Search for a structural AST pattern across a set of TypeScript/TSX files\n * using ast-grep's `findInFiles` API.\n *\n * @param opts - Pattern and file paths to search.\n * @returns An array of {@link PatternMatch} entries for all matching nodes.\n */\nexport async function patternSearch(opts: PatternSearchOptions): Promise<PatternMatch[]> {\n if (opts.filePaths.length === 0) return [];\n\n const matches: PatternMatch[] = [];\n\n await findInFiles(\n Lang.TypeScript,\n {\n paths: opts.filePaths,\n matcher: { rule: { pattern: opts.pattern } },\n },\n (err, nodes) => {\n if (err) return;\n for (const node of nodes) {\n const r = node.range();\n matches.push({\n filePath: node.getRoot().filename(),\n startLine: r.start.line + 1,\n endLine: r.end.line + 1,\n matchedText: node.text(),\n });\n }\n },\n );\n\n return matches;\n}\n",
|
|
39
|
-
"/**\n * SemanticLayer — tsc 기반 시맨틱 분석 계층.\n *\n * TscProgram + TypeCollector + SymbolGraph + ReferenceResolver + ImplementationFinder를\n * 하나의 facade로 통합한다.\n */\n\nimport ts from \"typescript\";\nimport { err, isErr, type Result } from \"@zipbul/result\";\nimport { gildashError, type GildashError } from \"../errors\";\nimport { TscProgram, type TscProgramOptions } from \"./tsc-program\";\nimport { TypeCollector } from \"./type-collector\";\nimport { SymbolGraph, type SymbolNode } from \"./symbol-graph\";\nimport { ReferenceResolver } from \"./reference-resolver\";\nimport { ImplementationFinder } from \"./implementation-finder\";\nimport type {\n ResolvedType,\n SemanticReference,\n Implementation,\n SemanticModuleInterface,\n SemanticExport,\n} from \"./types\";\n\n// ── DI options ───────────────────────────────────────────────────────────────\n\nexport interface SemanticLayerOptions extends TscProgramOptions {\n /** Override TypeCollector (for testing). */\n typeCollector?: TypeCollector;\n /** Override SymbolGraph (for testing). */\n symbolGraph?: SymbolGraph;\n /** Override ReferenceResolver (for testing). */\n referenceResolver?: ReferenceResolver;\n /** Override ImplementationFinder (for testing). */\n implementationFinder?: ImplementationFinder;\n}\n\n// ── 선언 식별 헬퍼 ───────────────────────────────────────────────────────────\n\n/** export 키워드가 있는지 확인 */\nfunction hasExportModifier(node: ts.Node): boolean {\n return (\n ts.canHaveModifiers(node) &&\n ts.getModifiers(node)?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) === true\n );\n}\n\n/** 선언 노드의 kind를 문자열로 분류 */\nfunction classifyDeclKind(node: ts.Node): string {\n if (ts.isFunctionDeclaration(node)) return \"function\";\n if (ts.isClassDeclaration(node)) return \"class\";\n if (ts.isInterfaceDeclaration(node)) return \"interface\";\n if (ts.isTypeAliasDeclaration(node)) return \"type\";\n if (ts.isEnumDeclaration(node)) return \"enum\";\n if (ts.isVariableDeclaration(node)) return \"const\";\n if (ts.isVariableStatement(node)) return \"const\";\n return \"unknown\";\n}\n\n/** charCode가 JS 식별자 문자(letter, digit, _, $)인지 판별 */\nfunction isIdentifierChar(charCode: number): boolean {\n // a-z\n if (charCode >= 0x61 && charCode <= 0x7a) return true;\n // A-Z\n if (charCode >= 0x41 && charCode <= 0x5a) return true;\n // 0-9\n if (charCode >= 0x30 && charCode <= 0x39) return true;\n // _ or $\n if (charCode === 0x5f || charCode === 0x24) return true;\n return false;\n}\n\n// ── SemanticLayer ────────────────────────────────────────────────────────────\n\nexport class SemanticLayer {\n readonly #program: TscProgram;\n readonly #typeCollector: TypeCollector;\n readonly #symbolGraph: SymbolGraph;\n readonly #referenceResolver: ReferenceResolver;\n readonly #implementationFinder: ImplementationFinder;\n #isDisposed = false;\n\n private constructor(\n program: TscProgram,\n typeCollector: TypeCollector,\n symbolGraph: SymbolGraph,\n referenceResolver: ReferenceResolver,\n implementationFinder: ImplementationFinder,\n ) {\n this.#program = program;\n this.#typeCollector = typeCollector;\n this.#symbolGraph = symbolGraph;\n this.#referenceResolver = referenceResolver;\n this.#implementationFinder = implementationFinder;\n }\n\n /**\n * Create a SemanticLayer from a tsconfig.json path.\n *\n * Internally creates TscProgram and all sub-modules.\n * DI overrides via `options` for testing.\n */\n static create(\n tsconfigPath: string,\n options: SemanticLayerOptions = {},\n ): Result<SemanticLayer, GildashError> {\n const programResult = TscProgram.create(tsconfigPath, {\n readConfigFile: options.readConfigFile,\n resolveNonTrackedFile: options.resolveNonTrackedFile,\n });\n if (isErr(programResult)) return programResult;\n\n const program = programResult;\n\n const typeCollector = options.typeCollector ?? new TypeCollector(program);\n const symbolGraph = options.symbolGraph ?? new SymbolGraph(program);\n const referenceResolver = options.referenceResolver ?? new ReferenceResolver(program);\n const implementationFinder = options.implementationFinder ?? new ImplementationFinder(program);\n\n return new SemanticLayer(\n program,\n typeCollector,\n symbolGraph,\n referenceResolver,\n implementationFinder,\n );\n }\n\n // ── Read-only state ─────────────────────────────────────────────────────\n\n get isDisposed(): boolean {\n return this.#isDisposed;\n }\n\n // ── Type collection ─────────────────────────────────────────────────────\n\n collectTypeAt(filePath: string, position: number): ResolvedType | null {\n this.#assertNotDisposed();\n return this.#typeCollector.collectAt(filePath, position);\n }\n\n collectFileTypes(filePath: string): Map<number, ResolvedType> {\n this.#assertNotDisposed();\n return this.#typeCollector.collectFile(filePath);\n }\n\n // ── Semantic references ─────────────────────────────────────────────────\n\n findReferences(filePath: string, position: number): SemanticReference[] {\n this.#assertNotDisposed();\n return this.#referenceResolver.findAt(filePath, position);\n }\n\n // ── Implementations ─────────────────────────────────────────────────────\n\n findImplementations(filePath: string, position: number): Implementation[] {\n this.#assertNotDisposed();\n return this.#implementationFinder.findAt(filePath, position);\n }\n\n // ── Symbol graph ────────────────────────────────────────────────────────\n\n getSymbolNode(filePath: string, position: number): SymbolNode | null {\n this.#assertNotDisposed();\n return this.#symbolGraph.get(filePath, position);\n }\n\n // ── Module interface ────────────────────────────────────────────────────\n\n getModuleInterface(filePath: string): SemanticModuleInterface {\n this.#assertNotDisposed();\n\n const typeMap = this.#typeCollector.collectFile(filePath);\n const exports: SemanticExport[] = [];\n\n // AST에서 export 선언을 탐색\n const tsProgram = this.#program.getProgram();\n const sourceFile = tsProgram.getSourceFile(filePath);\n if (!sourceFile) return { filePath, exports };\n\n function visit(node: ts.Node): void {\n // export const/let/var — VariableStatement 레벨에서 export 체크\n if (ts.isVariableStatement(node) && hasExportModifier(node)) {\n for (const decl of node.declarationList.declarations) {\n if (ts.isIdentifier(decl.name)) {\n const nameStartPos = decl.name.getStart(sourceFile!);\n const resolvedType = typeMap.get(nameStartPos) ?? null;\n exports.push({\n name: decl.name.text,\n kind: \"const\",\n resolvedType,\n });\n }\n }\n return; // 자식 노드 재방문 불필요\n }\n\n // export function / class / interface / type / enum\n if (\n (ts.isFunctionDeclaration(node) ||\n ts.isClassDeclaration(node) ||\n ts.isInterfaceDeclaration(node) ||\n ts.isTypeAliasDeclaration(node) ||\n ts.isEnumDeclaration(node)) &&\n hasExportModifier(node) &&\n node.name\n ) {\n const nameNode = node.name;\n const nameStartPos = nameNode.getStart(sourceFile!);\n const resolvedType = typeMap.get(nameStartPos) ?? null;\n exports.push({\n name: nameNode.text,\n kind: classifyDeclKind(node),\n resolvedType,\n });\n return;\n }\n\n ts.forEachChild(node, visit);\n }\n\n visit(sourceFile);\n\n return { filePath, exports };\n }\n\n // ── Incremental update ──────────────────────────────────────────────────\n\n notifyFileChanged(filePath: string, content: string): void {\n if (this.#isDisposed) return;\n this.#program.notifyFileChanged(filePath, content);\n this.#symbolGraph.invalidate(filePath);\n }\n\n /**\n * Remove a tracked file from the tsc program and invalidate its symbol graph entries.\n *\n * Call this when a file is deleted from disk so the LanguageService no longer\n * reports stale references or type information for it.\n *\n * No-op if already disposed.\n */\n notifyFileDeleted(filePath: string): void {\n if (this.#isDisposed) return;\n this.#program.removeFile(filePath);\n this.#symbolGraph.invalidate(filePath);\n }\n\n // ── Position conversion ──────────────────────────────────────────────\n\n /**\n * Convert 1-based line + 0-based column to a byte offset using tsc SourceFile.\n * Returns `null` when the file is not part of the program.\n */\n lineColumnToPosition(filePath: string, line: number, column: number): number | null {\n this.#assertNotDisposed();\n const sourceFile = this.#program.getProgram().getSourceFile(filePath);\n if (!sourceFile) return null;\n try {\n return ts.getPositionOfLineAndCharacter(sourceFile, line - 1, column);\n } catch {\n return null;\n }\n }\n\n // ── Name position lookup ────────────────────────────────────────────────\n\n /**\n * Find the byte offset of a symbol **name** starting from its declaration position.\n *\n * `declarationPos` typically points to the `export` keyword (the declaration start\n * stored in the DB), while the symbol name sits a few tokens ahead.\n * Uses a simple text search to locate the first occurrence of `name` after `declarationPos`.\n *\n * Returns `null` when the file is not in the program or the name is not found.\n */\n findNamePosition(filePath: string, declarationPos: number, name: string): number | null {\n this.#assertNotDisposed();\n const sourceFile = this.#program.getProgram().getSourceFile(filePath);\n if (!sourceFile) return null;\n const text = sourceFile.getFullText();\n let searchFrom = declarationPos;\n while (searchFrom < text.length) {\n const idx = text.indexOf(name, searchFrom);\n if (idx < 0) return null;\n\n // Word boundary check: preceding char must be non-identifier, or idx === 0\n const before = idx > 0 ? text.charCodeAt(idx - 1) : 0x20; // space\n const after = idx + name.length < text.length ? text.charCodeAt(idx + name.length) : 0x20;\n if (!isIdentifierChar(before) && !isIdentifierChar(after)) {\n return idx;\n }\n\n searchFrom = idx + 1;\n }\n return null;\n }\n\n // ── Lifecycle ───────────────────────────────────────────────────────────\n\n dispose(): void {\n if (this.#isDisposed) return;\n this.#isDisposed = true;\n this.#program.dispose();\n this.#symbolGraph.clear();\n }\n\n // ── Internal ────────────────────────────────────────────────────────────\n\n #assertNotDisposed(): void {\n if (this.#isDisposed) {\n throw new Error(\"SemanticLayer is disposed\");\n }\n }\n}\n",
|
|
40
|
-
"/**\n * TscProgram — tsc Program/TypeChecker/LanguageService lifecycle manager.\n *\n * Wraps `ts.createLanguageService()` with a custom `LanguageServiceHost`\n * that tracks file versions in-memory for incremental updates.\n *\n * All I/O is injected via the `TscProgramOptions` DI parameters so that\n * unit tests can run without touching the filesystem.\n */\n\nimport ts from \"typescript\";\nimport path from \"node:path\";\nimport { err, type Result } from \"@zipbul/result\";\nimport { gildashError, type GildashError } from \"../errors\";\n\n// ── DI contracts ─────────────────────────────────────────────────────────────\n\n/**\n * Reads a file at `path` and returns its content, or `undefined` if missing.\n */\nexport type ReadConfigFileFn = (path: string) => string | undefined;\n\n/**\n * Resolves content for files NOT tracked by the user project\n * (e.g. TypeScript lib declarations on disk).\n * Returns file content or `undefined` if not found.\n */\nexport type ResolveNonTrackedFileFn = (path: string) => string | undefined;\n\nexport interface TscProgramOptions {\n /** Reads tsconfig.json content. Injected for testability. */\n readConfigFile?: ReadConfigFileFn;\n /** Resolves non-tracked files (ts libs, node_modules). Injected for testability. */\n resolveNonTrackedFile?: ResolveNonTrackedFileFn;\n}\n\n// ── Default I/O (Bun fs) ────────────────────────────────────────────────────\n\nfunction defaultReadConfigFile(filePath: string): string | undefined {\n try {\n // Synchronous read — ts.readConfigFile expects sync callback\n const fs = require(\"node:fs\");\n return fs.readFileSync(filePath, \"utf-8\") as string;\n } catch {\n return undefined;\n }\n}\n\nfunction defaultResolveNonTrackedFile(filePath: string): string | undefined {\n try {\n const fs = require(\"node:fs\");\n return fs.readFileSync(filePath, \"utf-8\") as string;\n } catch {\n return undefined;\n }\n}\n\n// ── TscProgram ──────────────────────────────────────────────────────────────\n\nexport class TscProgram {\n #languageService: ts.LanguageService;\n #host: TscLanguageServiceHost;\n #isDisposed = false;\n\n // ── Testing hook ────────────────────────────────────────────────────────\n\n /** @internal — exposed for unit test verification only. */\n readonly __testing__: { host: ts.LanguageServiceHost };\n\n private constructor(languageService: ts.LanguageService, host: TscLanguageServiceHost) {\n this.#languageService = languageService;\n this.#host = host;\n this.__testing__ = { host };\n }\n\n /**\n * Create a TscProgram from a tsconfig.json path.\n *\n * Parses the config, creates a LanguageServiceHost, and initializes the LanguageService.\n * Returns `Err<GildashError>` on config read/parse failure.\n */\n static create(\n tsconfigPath: string,\n options: TscProgramOptions = {},\n ): Result<TscProgram, GildashError> {\n const readConfigFn = options.readConfigFile ?? defaultReadConfigFile;\n const resolveNonTracked = options.resolveNonTrackedFile ?? defaultResolveNonTrackedFile;\n\n const projectDir = path.dirname(tsconfigPath);\n\n // 1. Read tsconfig.json content\n const configContent = readConfigFn(tsconfigPath);\n if (configContent === undefined) {\n return err(gildashError(\"semantic\", `tsconfig not found: ${tsconfigPath}`));\n }\n\n // 2. Parse JSON via ts.parseJsonText (handles JSONC comments)\n const jsonSourceFile = ts.parseJsonText(tsconfigPath, configContent);\n\n // parseDiagnostics exists at runtime on every SourceFile but is not in the public typings.\n const parseDiags = (jsonSourceFile as unknown as { parseDiagnostics?: ts.Diagnostic[] })\n .parseDiagnostics;\n if (parseDiags && parseDiags.length > 0) {\n const msg = parseDiags\n .map((d) => ts.flattenDiagnosticMessageText(d.messageText, \"\\n\"))\n .join(\"; \");\n return err(gildashError(\"semantic\", `tsconfig parse error: ${msg}`));\n }\n\n // 3. Parse config content into compilerOptions + fileNames\n const parsed = ts.parseJsonSourceFileConfigFileContent(\n jsonSourceFile,\n {\n useCaseSensitiveFileNames: true,\n readDirectory: () => [],\n fileExists: (p) => readConfigFn(p) !== undefined || resolveNonTracked(p) !== undefined,\n readFile: (p) => readConfigFn(p) ?? resolveNonTracked(p),\n },\n projectDir,\n );\n\n if (parsed.errors.length > 0) {\n // TS18003 \"No inputs were found in config file\" is expected — files are added\n // dynamically via notifyFileChanged, so the initial program has no source files.\n const fatalErrors = parsed.errors.filter(\n (d) => d.category === ts.DiagnosticCategory.Error && d.code !== 18003,\n );\n if (fatalErrors.length > 0) {\n const msg = fatalErrors\n .map((d) => ts.flattenDiagnosticMessageText(d.messageText, \"\\n\"))\n .join(\"; \");\n return err(gildashError(\"semantic\", `tsconfig compile error: ${msg}`));\n }\n }\n\n // 4. Create the host + LanguageService\n const host = new TscLanguageServiceHost(\n parsed.fileNames,\n parsed.options,\n projectDir,\n resolveNonTracked,\n );\n\n const languageService = ts.createLanguageService(host);\n\n return new TscProgram(languageService, host);\n }\n\n // ── Public API ──────────────────────────────────────────────────────────\n\n get isDisposed(): boolean {\n return this.#isDisposed;\n }\n\n getProgram(): ts.Program {\n this.#assertNotDisposed();\n const program = this.#languageService.getProgram();\n if (!program) {\n throw new Error(\"TscProgram: LanguageService returned null Program\");\n }\n return program;\n }\n\n getChecker(): ts.TypeChecker {\n this.#assertNotDisposed();\n return this.getProgram().getTypeChecker();\n }\n\n getLanguageService(): ts.LanguageService {\n this.#assertNotDisposed();\n return this.#languageService;\n }\n\n /**\n * Notify that a file's content has changed (or a new file was added).\n * Bumps the internal version so the LanguageService will re-evaluate on next query.\n *\n * No-op if already disposed.\n */\n notifyFileChanged(filePath: string, content: string): void {\n if (this.#isDisposed) return;\n this.#host.updateFile(filePath, content);\n }\n\n /**\n * Remove a tracked file from the LanguageService host.\n * After removal the file will no longer appear in `getScriptFileNames()`\n * and `getScriptSnapshot()` will return `undefined` for it.\n *\n * No-op if already disposed or the file was never tracked.\n */\n removeFile(filePath: string): void {\n if (this.#isDisposed) return;\n this.#host.removeFile(filePath);\n }\n\n /**\n * Dispose the LanguageService and release references.\n * Idempotent — safe to call multiple times.\n */\n dispose(): void {\n if (this.#isDisposed) return;\n this.#isDisposed = true;\n this.#languageService.dispose();\n }\n\n #assertNotDisposed(): void {\n if (this.#isDisposed) {\n throw new Error(\"TscProgram is disposed\");\n }\n }\n}\n\n// ── LanguageServiceHost ─────────────────────────────────────────────────────\n\nclass TscLanguageServiceHost implements ts.LanguageServiceHost {\n #rootFileNames: string[];\n #compilerOptions: ts.CompilerOptions;\n #projectDir: string;\n #resolveNonTracked: ResolveNonTrackedFileFn;\n\n /** tracked file path → { version: number, content: string } */\n #files = new Map<string, { version: number; content: string }>();\n\n constructor(\n rootFileNames: string[],\n compilerOptions: ts.CompilerOptions,\n projectDir: string,\n resolveNonTracked: ResolveNonTrackedFileFn,\n ) {\n this.#rootFileNames = [...rootFileNames];\n this.#compilerOptions = compilerOptions;\n this.#projectDir = projectDir;\n this.#resolveNonTracked = resolveNonTracked;\n }\n\n // ── File tracking ───────────────────────────────────────────────────────\n\n updateFile(filePath: string, content: string): void {\n const existing = this.#files.get(filePath);\n if (existing) {\n existing.version += 1;\n existing.content = content;\n } else {\n this.#files.set(filePath, { version: 1, content });\n }\n }\n\n removeFile(filePath: string): void {\n this.#files.delete(filePath);\n this.#rootFileNames = this.#rootFileNames.filter((f) => f !== filePath);\n }\n\n // ── ts.LanguageServiceHost implementation ───────────────────────────────\n\n getScriptFileNames(): string[] {\n const tracked = [...this.#files.keys()];\n const rootsNotTracked = this.#rootFileNames.filter((f) => !this.#files.has(f));\n return [...rootsNotTracked, ...tracked];\n }\n\n getScriptVersion(fileName: string): string {\n const entry = this.#files.get(fileName);\n return entry ? String(entry.version) : \"0\";\n }\n\n getScriptSnapshot(fileName: string): ts.IScriptSnapshot | undefined {\n // 1. Tracked files\n const entry = this.#files.get(fileName);\n if (entry) {\n return ts.ScriptSnapshot.fromString(entry.content);\n }\n\n // 2. Non-tracked files (ts libs, etc.)\n const content = this.#resolveNonTracked(fileName);\n if (content !== undefined) {\n return ts.ScriptSnapshot.fromString(content);\n }\n\n return undefined;\n }\n\n getCurrentDirectory(): string {\n return this.#projectDir;\n }\n\n getCompilationSettings(): ts.CompilerOptions {\n return this.#compilerOptions;\n }\n\n getDefaultLibFileName(options: ts.CompilerOptions): string {\n return ts.getDefaultLibFilePath(options);\n }\n\n fileExists(filePath: string): boolean {\n if (this.#files.has(filePath)) return true;\n return this.#resolveNonTracked(filePath) !== undefined;\n }\n\n readFile(filePath: string): string | undefined {\n const entry = this.#files.get(filePath);\n if (entry) return entry.content;\n return this.#resolveNonTracked(filePath);\n }\n}\n",
|
|
41
|
-
"/**\n * TypeCollector — tsc TypeChecker 직접 호출로 심볼의 ResolvedType을 수집한다.\n *\n * TscProgram에서 Program/TypeChecker를 가져와 AST를 탐색하고\n * 각 심볼 위치의 타입을 ResolvedType으로 변환한다.\n */\n\nimport ts from \"typescript\";\nimport type { ResolvedType } from \"./types\";\nimport type { TscProgram } from \"./tsc-program\";\nimport { findNodeAtPosition } from \"./ast-node-utils\";\n\n// ── ResolvedType 빌더 ────────────────────────────────────────────────────────\n\n/** TypeReference 여부 판별 (generic instantiation). */\nfunction isTypeReference(type: ts.Type): type is ts.TypeReference {\n return (\n !!(type.flags & ts.TypeFlags.Object) &&\n !!((type as ts.ObjectType).objectFlags & ts.ObjectFlags.Reference)\n );\n}\n\n/**\n * `ts.Type`을 `ResolvedType`으로 재귀 변환한다.\n *\n * 순환 타입에 대비해 `depth`로 재귀 깊이를 제한한다.\n */\nfunction buildResolvedType(\n checker: ts.TypeChecker,\n type: ts.Type,\n depth = 0,\n): ResolvedType {\n const text = checker.typeToString(type);\n const flags = type.flags;\n\n const isUnion = !!(flags & ts.TypeFlags.Union);\n const isIntersection = !!(flags & ts.TypeFlags.Intersection);\n\n // TypeReference의 구체화된 타입 인자를 public API로 가져온다.\n // (type as ts.TypeReference).typeArguments 대신 checker.getTypeArguments() 사용.\n let typeArgs: readonly ts.Type[] | undefined;\n if (depth < 8 && isTypeReference(type)) {\n const args = checker.getTypeArguments(type);\n if (args.length > 0) typeArgs = args;\n }\n\n // isGeneric: 타입 파라미터 자체이거나 타입 인자가 구체화된 TypeReference\n const isGeneric =\n !!(flags & ts.TypeFlags.TypeParameter) ||\n (typeArgs !== undefined && typeArgs.length > 0);\n\n // union / intersection 구성원 재귀 빌드\n let members: ResolvedType[] | undefined;\n if (isUnion && depth < 8) {\n members = (type as ts.UnionType).types.map((t) =>\n buildResolvedType(checker, t, depth + 1),\n );\n } else if (isIntersection && depth < 8) {\n members = (type as ts.IntersectionType).types.map((t) =>\n buildResolvedType(checker, t, depth + 1),\n );\n }\n\n // 타입 인자 재귀 빌드\n let typeArguments: ResolvedType[] | undefined;\n if (typeArgs && typeArgs.length > 0) {\n typeArguments = typeArgs.map((t) =>\n buildResolvedType(checker, t, depth + 1),\n );\n }\n\n return { text, flags, isUnion, isIntersection, isGeneric, members, typeArguments };\n}\n\n// ── 선언 위치 순회 ───────────────────────────────────────────────────────────\n\n/** 선언 이름인 Identifier 노드인지 판별한다. */\nfunction isNamedDeclaration(node: ts.Node): node is ts.NamedDeclaration {\n return (\n ts.isFunctionDeclaration(node) ||\n ts.isVariableDeclaration(node) ||\n ts.isClassDeclaration(node) ||\n ts.isInterfaceDeclaration(node) ||\n ts.isTypeAliasDeclaration(node) ||\n ts.isEnumDeclaration(node) ||\n ts.isMethodDeclaration(node) ||\n ts.isPropertyDeclaration(node) ||\n ts.isPropertySignature(node) ||\n ts.isMethodSignature(node)\n );\n}\n\n// ── TypeCollector ─────────────────────────────────────────────────────────────\n\nexport class TypeCollector {\n constructor(private readonly program: TscProgram) {}\n\n /**\n * `filePath`의 `position` 위치(0-based 문자 오프셋)에 있는 심볼의 타입을 수집한다.\n *\n * - 파일이 없거나 위치에 식별자가 없으면 `null` 반환\n * - `TscProgram이` disposed 상태이면 throw (getProgram이 throw)\n */\n collectAt(filePath: string, position: number): ResolvedType | null {\n // disposed 체크는 getProgram/getChecker가 대신 throw\n const tsProgram = this.program.getProgram();\n const checker = this.program.getChecker();\n\n if (position < 0) return null;\n\n const sourceFile = tsProgram.getSourceFile(filePath);\n if (!sourceFile) return null;\n\n if (position >= sourceFile.getEnd()) return null;\n\n const node = findNodeAtPosition(sourceFile, position);\n if (!node) return null;\n\n // 식별자가 아니면 (keyword, 구두점 등) 타입 수집 불가\n if (!ts.isIdentifier(node)) return null;\n\n try {\n const type = checker.getTypeAtLocation(node);\n // error/unknown flag 조합으로 never에 가까운 타입은 그대로 전달\n return buildResolvedType(checker, type);\n } catch {\n return null;\n }\n }\n\n /**\n * `filePath`에서 모든 선언 이름 심볼의 타입을 수집한다.\n *\n * 반환 Map의 key = 선언 이름 식별자의 시작 위치(0-based).\n * 파일이 없으면 빈 Map 반환.\n * `TscProgram`이 disposed 상태이면 throw.\n */\n collectFile(filePath: string): Map<number, ResolvedType> {\n const result = new Map<number, ResolvedType>();\n\n const tsProgram = this.program.getProgram();\n const checker = this.program.getChecker();\n\n const sourceFile = tsProgram.getSourceFile(filePath);\n if (!sourceFile) return result;\n\n function visit(node: ts.Node): void {\n if (isNamedDeclaration(node) && node.name && ts.isIdentifier(node.name)) {\n const nameNode = node.name;\n try {\n const type = checker.getTypeAtLocation(nameNode);\n const pos = nameNode.getStart(sourceFile!);\n result.set(pos, buildResolvedType(checker, type));\n } catch {\n // 타입 수집 실패 심볼은 건너뜀\n }\n }\n ts.forEachChild(node, visit);\n }\n\n visit(sourceFile);\n return result;\n }\n}\n",
|
|
42
|
-
"/**\n * Shared AST node utilities for the semantic layer.\n */\n\nimport ts from \"typescript\";\n\n/**\n * `pos` 위치의 가장 작은(innermost) 노드를 반환한다.\n * 범위 밖이면 `undefined`.\n */\nexport function findNodeAtPosition(\n sourceFile: ts.SourceFile,\n pos: number,\n): ts.Node | undefined {\n if (pos < 0 || pos >= sourceFile.getEnd()) return undefined;\n\n function visit(node: ts.Node): ts.Node | undefined {\n const start = node.getStart(sourceFile, false);\n const end = node.getEnd();\n\n if (pos < start || pos >= end) return undefined;\n\n // 자식 중 더 좁은 노드 탐색\n let found: ts.Node | undefined;\n ts.forEachChild(node, (child) => {\n if (!found) found = visit(child);\n });\n return found ?? node;\n }\n\n return visit(sourceFile);\n}\n",
|
|
43
|
-
"/**\n * SymbolGraph — tsc Symbol API로 심볼의 계층(parent/members/exports)을 탐색하고\n * LRU 캐시로 결과를 재사용한다.\n */\n\nimport ts from \"typescript\";\nimport { LruCache } from \"../common/lru-cache\";\nimport type { TscProgram } from \"./tsc-program\";\nimport { findNodeAtPosition } from \"./ast-node-utils\";\n\n// ── Public types ─────────────────────────────────────────────────────────────\n\nexport interface SymbolNode {\n /** 심볼 이름 (`ts.Symbol.getName()`) */\n name: string;\n /** 첫 번째 선언이 위치한 파일 경로 */\n filePath: string;\n /** 첫 번째 선언의 이름 식별자 `getStart()` 오프셋 */\n position: number;\n /** 컨테이너 심볼 (namespace·class·enum의 멤버인 경우) */\n parent?: SymbolNode;\n /** 클래스·인터페이스·enum의 멤버 심볼 목록 */\n members?: SymbolNode[];\n /** namespace의 export 심볼 목록 */\n exports?: SymbolNode[];\n}\n\n// ── 내부 상수 ─────────────────────────────────────────────────────────────────\n\nconst DEFAULT_CAPACITY = 1_000;\n\n/** tsc 내부 Symbol — parent는 공개 API에 없으므로 별도 타입으로 접근한다. */\ntype InternalSymbol = ts.Symbol & { parent?: ts.Symbol };\n/** members/exports 재귀 최대 깊이 */\nconst MAX_MEMBER_DEPTH = 1;\n\n// ── SymbolNode 빌더 ──────────────────────────────────────────────────────────\n\n/**\n * 컨테이너 심볼을 name·filePath·position만으로 얕게 빌드한다.\n * (parent-of-parent 재귀 방지)\n */\nfunction buildParentNode(symbol: ts.Symbol): SymbolNode {\n const decl = symbol.declarations?.[0];\n const sourceFile = decl?.getSourceFile();\n const nameNode = decl\n ? ts.getNameOfDeclaration(decl as ts.Declaration)\n : undefined;\n return {\n name: symbol.getName(),\n filePath: sourceFile?.fileName ?? \"\",\n position:\n nameNode?.getStart(sourceFile, false) ??\n decl?.getStart(sourceFile, false) ??\n 0,\n };\n}\n\n/**\n * `ts.Symbol`을 `SymbolNode`로 변환한다.\n *\n * @param symbol 변환할 심볼\n * @param depth 현재 재귀 깊이 (members/exports 탐색 제한)\n */\nfunction buildSymbolNode(symbol: InternalSymbol, depth = 0): SymbolNode {\n const decl = symbol.declarations?.[0];\n const sourceFile = decl?.getSourceFile();\n const nameNode = decl\n ? ts.getNameOfDeclaration(decl as ts.Declaration)\n : undefined;\n const filePath = sourceFile?.fileName ?? \"\";\n const position =\n nameNode?.getStart(sourceFile, false) ??\n decl?.getStart(sourceFile, false) ??\n 0;\n\n const node: SymbolNode = {\n name: symbol.getName(),\n filePath,\n position,\n };\n\n // parent — 컨테이너 심볼이 있으면 얕게 빌드\n const internalSym = symbol as InternalSymbol;\n if (internalSym.parent) {\n node.parent = buildParentNode(internalSym.parent);\n }\n\n if (depth < MAX_MEMBER_DEPTH) {\n const flags = symbol.flags;\n const isEnum = !!(flags & ts.SymbolFlags.Enum);\n const isNamespace = !!(\n flags &\n (ts.SymbolFlags.NamespaceModule | ts.SymbolFlags.ValueModule)\n );\n const isClassOrInterface = !!(\n flags &\n (ts.SymbolFlags.Class | ts.SymbolFlags.Interface)\n );\n\n // members — class/interface: symbol.members / enum: symbol.exports\n if (isEnum && symbol.exports && symbol.exports.size > 0) {\n const members: SymbolNode[] = [];\n symbol.exports.forEach((memberSym) => {\n members.push(buildSymbolNode(memberSym, depth + 1));\n });\n node.members = members;\n } else if (isClassOrInterface && symbol.members && symbol.members.size > 0) {\n const members: SymbolNode[] = [];\n symbol.members.forEach((memberSym) => {\n members.push(buildSymbolNode(memberSym, depth + 1));\n });\n node.members = members;\n }\n\n // exports — namespace: symbol.exports\n if (isNamespace && symbol.exports && symbol.exports.size > 0) {\n const exports: SymbolNode[] = [];\n symbol.exports.forEach((exportSym) => {\n exports.push(buildSymbolNode(exportSym, depth + 1));\n });\n node.exports = exports;\n }\n }\n\n return node;\n}\n\n// ── SymbolGraph ───────────────────────────────────────────────────────────────\n\nexport class SymbolGraph {\n readonly #program: TscProgram;\n readonly #cache: LruCache<string, SymbolNode>;\n /** filePath → Set<cacheKey> (invalidate 효율화용) */\n readonly #fileKeys = new Map<string, Set<string>>();\n\n constructor(program: TscProgram, capacity = DEFAULT_CAPACITY) {\n this.#program = program;\n this.#cache = new LruCache<string, SymbolNode>(capacity);\n }\n\n /**\n * `filePath`의 `position` 위치 심볼을 `SymbolNode`로 반환한다.\n * - 프로그램이 dispose되었거나 심볼을 찾을 수 없으면 `null`을 반환한다.\n * - 결과는 LRU 캐시에 저장된다.\n */\n get(filePath: string, position: number): SymbolNode | null {\n // disposed 체크\n if (this.#program.isDisposed) return null;\n\n // 캐시 히트\n const cacheKey = `${filePath}:${position}`;\n const cached = this.#cache.get(cacheKey);\n if (cached !== undefined) return cached;\n\n // SourceFile 조회\n const prog = this.#program.getProgram();\n const sourceFile = prog.getSourceFile(filePath);\n if (!sourceFile) return null;\n\n // AST 탐색 — identifier 노드를 찾아야 함\n const node = findNodeAtPosition(sourceFile, position);\n if (!node || !ts.isIdentifier(node)) return null;\n\n // 심볼 조회\n const checker = this.#program.getChecker();\n const symbol = checker.getSymbolAtLocation(node);\n if (!symbol) return null;\n\n // SymbolNode 빌드 + 캐시 저장\n const symbolNode = buildSymbolNode(symbol as InternalSymbol);\n this.#cache.set(cacheKey, symbolNode);\n\n // filePath → keys 인덱스 갱신\n let keys = this.#fileKeys.get(filePath);\n if (!keys) {\n keys = new Set<string>();\n this.#fileKeys.set(filePath, keys);\n }\n keys.add(cacheKey);\n\n return symbolNode;\n }\n\n /**\n * `filePath`에 해당하는 캐시 항목을 모두 제거한다.\n * 파일 변경 시 호출하여 stale 결과를 무효화한다.\n */\n invalidate(filePath: string): void {\n const keys = this.#fileKeys.get(filePath);\n if (keys) {\n for (const key of keys) {\n this.#cache.delete(key);\n }\n this.#fileKeys.delete(filePath);\n }\n }\n\n /** 캐시 전체를 초기화한다. */\n clear(): void {\n this.#cache.clear();\n this.#fileKeys.clear();\n }\n}\n",
|
|
44
|
-
"/**\n * ReferenceResolver — LanguageService.findReferences 기반 시맨틱 참조 탐색.\n *\n * 텍스트 검색과 달리 심볼 identity 기반으로 참조를 찾으므로\n * rename, re-export, shadowing을 정확히 처리한다.\n */\n\nimport ts from \"typescript\";\nimport type { SemanticReference } from \"./types\";\nimport type { TscProgram } from \"./tsc-program\";\nimport { findNodeAtPosition } from \"./ast-node-utils\";\n\n// ── ReferenceResolver ─────────────────────────────────────────────────────────\n\nexport class ReferenceResolver {\n readonly #program: TscProgram;\n\n constructor(program: TscProgram) {\n this.#program = program;\n }\n\n /**\n * `filePath`의 `position` 위치 심볼에 대한 모든 참조를 찾는다.\n *\n * - 프로그램이 dispose되었거나 심볼을 찾을 수 없으면 빈 배열을 반환한다.\n * - LanguageService.findReferences를 사용하므로 cross-file 참조도 포함된다.\n */\n findAt(filePath: string, position: number): SemanticReference[] {\n // disposed 체크\n if (this.#program.isDisposed) return [];\n\n // SourceFile 조회\n const prog = this.#program.getProgram();\n const sourceFile = prog.getSourceFile(filePath);\n if (!sourceFile) return [];\n\n // AST 탐색 — identifier 노드만 허용\n const node = findNodeAtPosition(sourceFile, position);\n if (!node || !ts.isIdentifier(node)) return [];\n\n // LanguageService.findReferences\n const ls = this.#program.getLanguageService();\n const referencedSymbols = ls.findReferences(filePath, position);\n if (!referencedSymbols || referencedSymbols.length === 0) return [];\n\n // SemanticReference[] 변환\n const results: SemanticReference[] = [];\n\n for (const refSymbol of referencedSymbols) {\n for (const entry of refSymbol.references) {\n const refSourceFile = prog.getSourceFile(entry.fileName);\n if (!refSourceFile) continue;\n\n const { line: lineZero, character: column } =\n refSourceFile.getLineAndCharacterOfPosition(entry.textSpan.start);\n\n results.push({\n filePath: entry.fileName,\n position: entry.textSpan.start,\n line: lineZero + 1, // 1-based\n column, // 0-based\n isDefinition: entry.isDefinition ?? false,\n isWrite: entry.isWriteAccess ?? false,\n });\n }\n }\n\n return results;\n }\n}\n",
|
|
45
|
-
"/**\n * ImplementationFinder — findImplementations + isTypeAssignableTo 기반 구현체 탐색.\n *\n * interface/abstract class의 구현체를 찾는다.\n * - LanguageService.getImplementationAtPosition: 명시적 + 일부 구조적 구현체\n * - TypeChecker.isTypeAssignableTo: 덕 타이핑 구현체 검증\n *\n * 명시적(`implements` 키워드) 구현과 구조적(duck-typing) 구현 모두 탐지한다.\n */\n\nimport ts from \"typescript\";\nimport type { Implementation } from \"./types\";\nimport type { TscProgram } from \"./tsc-program\";\nimport { findNodeAtPosition } from \"./ast-node-utils\";\n\n/**\n * `pos` 위치에서 가장 가까운 선언(declaration) 노드를 찾는다.\n * identifier에서 부모를 타고 올라가며 선언 노드를 탐색한다.\n */\nfunction findDeclarationAtPosition(\n sourceFile: ts.SourceFile,\n pos: number,\n): ts.Node | undefined {\n const node = findNodeAtPosition(sourceFile, pos);\n if (!node) return undefined;\n\n // 이미 선언 노드이면 바로 반환\n if (isDeclarationNode(node)) return node;\n\n // 부모를 타고 올라가며 선언 노드 탐색 (최대 5단계)\n let current: ts.Node | undefined = node.parent;\n for (let i = 0; i < 5 && current; i++) {\n if (isDeclarationNode(current)) return current;\n current = current.parent;\n }\n\n return node;\n}\n\nfunction isDeclarationNode(node: ts.Node): boolean {\n return (\n ts.isClassDeclaration(node) ||\n ts.isClassExpression(node) ||\n ts.isFunctionDeclaration(node) ||\n ts.isFunctionExpression(node) ||\n ts.isArrowFunction(node) ||\n ts.isVariableDeclaration(node) ||\n ts.isObjectLiteralExpression(node)\n );\n}\n\n// ── Kind 분류 ─────────────────────────────────────────────────────────────────\n\n/**\n * AST 노드에서 Implementation.kind를 결정한다.\n */\nfunction classifyKind(node: ts.Node): Implementation[\"kind\"] {\n if (ts.isClassDeclaration(node) || ts.isClassExpression(node)) {\n return \"class\";\n }\n\n if (\n ts.isFunctionDeclaration(node) ||\n ts.isFunctionExpression(node) ||\n ts.isArrowFunction(node)\n ) {\n return \"function\";\n }\n\n if (ts.isObjectLiteralExpression(node)) {\n return \"object\";\n }\n\n // VariableDeclaration → initializer 타입에 따라 분류\n if (ts.isVariableDeclaration(node) && node.initializer) {\n return classifyKind(node.initializer);\n }\n\n // default\n return \"class\";\n}\n\n// ── 심볼 이름 추출 ────────────────────────────────────────────────────────────\n\n/**\n * 선언 노드에서 심볼 이름을 추출한다.\n */\nfunction extractSymbolName(node: ts.Node, sourceFile: ts.SourceFile): string {\n // ClassDeclaration / FunctionDeclaration — name 프로퍼티\n if (ts.isClassDeclaration(node) || ts.isFunctionDeclaration(node)) {\n return node.name?.getText(sourceFile) ?? \"\";\n }\n\n // ClassExpression — name이 있을 수도 없을 수도\n if (ts.isClassExpression(node)) {\n return node.name?.getText(sourceFile) ?? \"\";\n }\n\n // VariableDeclaration — name identifier\n if (ts.isVariableDeclaration(node) && ts.isIdentifier(node.name)) {\n return node.name.getText(sourceFile);\n }\n\n // FunctionExpression\n if (ts.isFunctionExpression(node)) {\n return node.name?.getText(sourceFile) ?? \"\";\n }\n\n // ArrowFunction — 부모 VariableDeclaration에서 이름\n if (ts.isArrowFunction(node) && node.parent && ts.isVariableDeclaration(node.parent)) {\n if (ts.isIdentifier(node.parent.name)) {\n return node.parent.name.getText(sourceFile);\n }\n }\n\n // ObjectLiteralExpression — 부모 VariableDeclaration에서 이름\n if (ts.isObjectLiteralExpression(node) && node.parent && ts.isVariableDeclaration(node.parent)) {\n if (ts.isIdentifier(node.parent.name)) {\n return node.parent.name.getText(sourceFile);\n }\n }\n\n return \"\";\n}\n\n// ── isExplicit 판정 ───────────────────────────────────────────────────────────\n\n/**\n * 선언 노드가 `implements` 키워드를 사용하는지 확인한다.\n */\nfunction checkIsExplicit(node: ts.Node): boolean {\n // ClassDeclaration / ClassExpression만 implements 가능\n if (!ts.isClassDeclaration(node) && !ts.isClassExpression(node)) {\n return false;\n }\n\n const heritageClauses = node.heritageClauses;\n if (!heritageClauses) return false;\n\n return heritageClauses.some(\n (clause) => clause.token === ts.SyntaxKind.ImplementsKeyword,\n );\n}\n\n// ── ImplementationFinder ──────────────────────────────────────────────────────\n\nexport class ImplementationFinder {\n readonly #program: TscProgram;\n\n constructor(program: TscProgram) {\n this.#program = program;\n }\n\n /**\n * `filePath`의 `position` 위치 심볼에 대한 구현체를 찾는다.\n *\n * - 프로그램이 dispose되었거나 심볼을 찾을 수 없으면 빈 배열을 반환한다.\n * - 명시적 `implements` + 구조적 타이핑(duck-typing) 구현체 모두 포함한다.\n */\n findAt(filePath: string, position: number): Implementation[] {\n // Branch 1: disposed 체크\n if (this.#program.isDisposed) return [];\n\n // SourceFile 조회\n const prog = this.#program.getProgram();\n // Branch 2: sourceFile 없음\n const sourceFile = prog.getSourceFile(filePath);\n if (!sourceFile) return [];\n\n // Branch 3, 4: AST 탐색 — identifier 노드만 허용\n const node = findNodeAtPosition(sourceFile, position);\n if (!node || !ts.isIdentifier(node)) return [];\n\n // LanguageService.getImplementationAtPosition\n const ls = this.#program.getLanguageService();\n const implLocations = ls.getImplementationAtPosition(filePath, position);\n // Branch 5: 결과 없음\n if (!implLocations || implLocations.length === 0) return [];\n\n const results: Implementation[] = [];\n\n for (const loc of implLocations) {\n // interface/type alias 자체는 skip (구현체가 아님)\n if (\n loc.kind === ts.ScriptElementKind.interfaceElement ||\n loc.kind === ts.ScriptElementKind.typeElement\n ) {\n continue;\n }\n\n // Branch 6: sourceFile 없는 결과 entry skip\n const implSourceFile = prog.getSourceFile(loc.fileName);\n if (!implSourceFile) continue;\n\n // 선언 노드 탐색\n const declNode = findDeclarationAtPosition(implSourceFile, loc.textSpan.start);\n if (!declNode) continue;\n\n // Branch 7: kind 분류\n const kind = classifyKind(declNode);\n // symbolName 추출\n const symbolName = extractSymbolName(declNode, implSourceFile);\n // Branch 8: isExplicit 판정\n const isExplicit = checkIsExplicit(declNode);\n\n results.push({\n filePath: loc.fileName,\n symbolName,\n position: loc.textSpan.start,\n kind,\n isExplicit,\n });\n }\n\n return results;\n }\n}\n",
|
|
46
|
-
"import type { RelationRecord } from '../store/repositories/relation.repository';\n\nexport interface IDependencyGraphRepo {\n getByType(project: string, type: string): RelationRecord[];\n}\n\n/**\n * Directed import graph for dependency analysis.\n *\n * Build the graph once with {@link DependencyGraph.build}, then query\n * dependencies, dependents, cycles, and change-impact.\n *\n * @example\n * ```ts\n * const graph = new DependencyGraph({ relationRepo, project: 'my-app' });\n * graph.build();\n * graph.getDependencies('/src/a.ts'); // files that a.ts imports\n * graph.getDependents('/src/a.ts'); // files that import a.ts\n * graph.hasCycle(); // true if a circular import exists\n * ```\n */\nexport class DependencyGraph {\n private adjacencyList = new Map<string, Set<string>>();\n private reverseAdjacencyList = new Map<string, Set<string>>();\n\n constructor(\n private readonly options: {\n relationRepo: IDependencyGraphRepo;\n project: string;\n additionalProjects?: string[];\n },\n ) {}\n\n /**\n * Populate the graph by reading all `imports` relations from the store.\n *\n * Must be called before any query method.\n */\n build(): void {\n this.adjacencyList = new Map();\n this.reverseAdjacencyList = new Map();\n\n const projects = [this.options.project, ...(this.options.additionalProjects ?? [])];\n const relations = projects.flatMap(p => [\n ...this.options.relationRepo.getByType(p, 'imports'),\n ...this.options.relationRepo.getByType(p, 'type-references'),\n ...this.options.relationRepo.getByType(p, 're-exports'),\n ]);\n\n for (const rel of relations) {\n const { srcFilePath, dstFilePath } = rel;\n\n if (!this.adjacencyList.has(srcFilePath)) {\n this.adjacencyList.set(srcFilePath, new Set());\n }\n this.adjacencyList.get(srcFilePath)!.add(dstFilePath);\n\n // ensure destination node also appears as a key (with no outgoing edges)\n if (!this.adjacencyList.has(dstFilePath)) {\n this.adjacencyList.set(dstFilePath, new Set());\n }\n\n if (!this.reverseAdjacencyList.has(dstFilePath)) {\n this.reverseAdjacencyList.set(dstFilePath, new Set());\n }\n this.reverseAdjacencyList.get(dstFilePath)!.add(srcFilePath);\n }\n }\n\n /**\n * Incrementally patch the graph after a set of files changed or were deleted.\n *\n * For small change-sets this is much cheaper than a full {@link build}.\n *\n * @param changedFiles - Files whose edges may have changed.\n * @param deletedFiles - Files that were removed from the project.\n * @param getRelationsForFile - Callback to query current relations for a file.\n */\n patchFiles(\n changedFiles: string[],\n deletedFiles: string[],\n getRelationsForFile: (filePath: string) => Array<{ srcFilePath: string; dstFilePath: string }>,\n ): void {\n const affectedFiles = new Set([...changedFiles, ...deletedFiles]);\n\n // Remove all edges involving affected files\n for (const file of affectedFiles) {\n const outgoing = this.adjacencyList.get(file);\n if (outgoing) {\n for (const dst of outgoing) {\n this.reverseAdjacencyList.get(dst)?.delete(file);\n }\n outgoing.clear();\n }\n\n const incoming = this.reverseAdjacencyList.get(file);\n if (incoming) {\n for (const src of incoming) {\n this.adjacencyList.get(src)?.delete(file);\n }\n incoming.clear();\n }\n }\n\n // Remove deleted files entirely\n for (const file of deletedFiles) {\n this.adjacencyList.delete(file);\n this.reverseAdjacencyList.delete(file);\n }\n\n // Re-add edges for changed (non-deleted) files\n for (const file of changedFiles) {\n const relations = getRelationsForFile(file);\n for (const rel of relations) {\n if (!this.adjacencyList.has(rel.srcFilePath)) {\n this.adjacencyList.set(rel.srcFilePath, new Set());\n }\n this.adjacencyList.get(rel.srcFilePath)!.add(rel.dstFilePath);\n\n if (!this.adjacencyList.has(rel.dstFilePath)) {\n this.adjacencyList.set(rel.dstFilePath, new Set());\n }\n\n if (!this.reverseAdjacencyList.has(rel.dstFilePath)) {\n this.reverseAdjacencyList.set(rel.dstFilePath, new Set());\n }\n this.reverseAdjacencyList.get(rel.dstFilePath)!.add(rel.srcFilePath);\n }\n }\n }\n\n /**\n * Return the files that `filePath` directly imports.\n *\n * @param filePath - Absolute file path.\n */\n getDependencies(filePath: string): string[] {\n return Array.from(this.adjacencyList.get(filePath) ?? []);\n }\n\n /**\n * Return the files that directly import `filePath`.\n *\n * @param filePath - Absolute file path.\n */\n getDependents(filePath: string): string[] {\n return Array.from(this.reverseAdjacencyList.get(filePath) ?? []);\n }\n\n /**\n * Return all files that transitively depend on `filePath`\n * (breadth-first reverse walk).\n *\n * @param filePath - Absolute file path.\n */\n getTransitiveDependents(filePath: string): string[] {\n const visited = new Set<string>();\n const queue: string[] = [filePath];\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n for (const dependent of this.reverseAdjacencyList.get(current) ?? []) {\n if (!visited.has(dependent)) {\n visited.add(dependent);\n queue.push(dependent);\n }\n }\n }\n\n return Array.from(visited);\n }\n\n /**\n * Detect whether the import graph contains at least one cycle.\n *\n * Uses iterative DFS with a path-tracking set.\n *\n * @returns `true` if a circular dependency exists.\n */\n hasCycle(): boolean {\n const visited = new Set<string>();\n const inPath = new Set<string>();\n\n for (const startNode of this.adjacencyList.keys()) {\n if (visited.has(startNode)) continue;\n\n const stack: Array<{ node: string; entered: boolean }> = [{ node: startNode, entered: false }];\n\n while (stack.length > 0) {\n const current = stack.pop()!;\n\n if (current.entered) {\n inPath.delete(current.node);\n continue;\n }\n\n if (inPath.has(current.node)) {\n return true;\n }\n\n if (visited.has(current.node)) {\n continue;\n }\n\n visited.add(current.node);\n inPath.add(current.node);\n stack.push({ node: current.node, entered: true });\n\n for (const neighbor of this.adjacencyList.get(current.node) ?? []) {\n if (inPath.has(neighbor)) {\n return true;\n }\n if (!visited.has(neighbor)) {\n stack.push({ node: neighbor, entered: false });\n }\n }\n }\n }\n\n return false;\n }\n\n /**\n * Compute all files transitively affected by a set of changed files.\n *\n * Combines {@link getTransitiveDependents} for every changed file\n * and de-duplicates the result.\n *\n * @param changedFiles - Absolute paths of files that changed.\n * @returns Paths of all transitively-dependent files.\n */\n getAffectedByChange(changedFiles: string[]): string[] {\n const allAffected = new Set<string>();\n\n for (const file of changedFiles) {\n for (const dep of this.getTransitiveDependents(file)) {\n allAffected.add(dep);\n }\n }\n\n return Array.from(allAffected);\n }\n\n /**\n * Return the full import graph as an adjacency list.\n *\n * Each key is a file path (both source and destination files are included as keys).\n * The associated value lists the files it directly imports.\n *\n * @returns A new `Map<filePath, importedFilePaths[]>`.\n */\n getAdjacencyList(): Map<string, string[]> {\n const result = new Map<string, string[]>();\n for (const [node, edges] of this.adjacencyList) {\n result.set(node, Array.from(edges));\n }\n return result;\n }\n\n /**\n * Return all files that `filePath` transitively imports\n * (breadth-first forward walk).\n *\n * @param filePath - Absolute file path.\n * @returns Paths of all transitively-imported files. Does not include `filePath` itself\n * unless a cycle exists.\n */\n getTransitiveDependencies(filePath: string): string[] {\n const visited = new Set<string>();\n const queue: string[] = [filePath];\n\n while (queue.length > 0) {\n const current = queue.shift()!;\n for (const dep of this.adjacencyList.get(current) ?? []) {\n if (!visited.has(dep)) {\n visited.add(dep);\n queue.push(dep);\n }\n }\n }\n\n return Array.from(visited);\n }\n\n /**\n * Return the distinct cycle paths in the import graph.\n *\n * Each cycle is represented as a list of file paths in canonical form\n * (rotated so the lexicographically smallest node comes first).\n * Duplicate cycles are deduplicated.\n *\n * Tarjan SCC + Johnson's circuits — 모든 elementary circuit 보장.\n * `maxCycles` 옵션으로 반환 개수를 제한할 수 있습니다.\n *\n * @param options.maxCycles - Maximum number of cycles to return. Defaults to `Infinity`.\n * @returns An array of cycles, where each cycle is a `string[]` of file paths\n * in canonical form (lexicographic rotation, smallest node first).\n * Returns an empty array when no cycles exist.\n */\n getCyclePaths(options?: { maxCycles?: number }): string[][] {\n const maxCycles = options?.maxCycles ?? Infinity;\n\n if (maxCycles <= 0) return [];\n\n // Build a Map<string, string[]> snapshot of the adjacencyList\n const adjacency = new Map<string, ReadonlyArray<string>>();\n for (const [node, edges] of this.adjacencyList) {\n adjacency.set(node, Array.from(edges));\n }\n\n return detectCycles(adjacency, maxCycles);\n }\n}\n\n// ─── Tarjan SCC + Johnson's circuits (module-level helpers) ───\n\nconst compareStrings = (a: string, b: string): number => a.localeCompare(b);\n\n/**\n * Normalize a cycle to canonical form:\n * strip trailing duplicate, rotate so the lexicographically smallest node is first.\n */\nfunction normalizeCycle(cycle: ReadonlyArray<string>): string[] {\n const unique =\n cycle.length > 1 && cycle[0] === cycle[cycle.length - 1]\n ? cycle.slice(0, -1)\n : [...cycle];\n\n if (unique.length === 0) return [];\n\n let best = unique;\n for (let i = 1; i < unique.length; i++) {\n const rotated = unique.slice(i).concat(unique.slice(0, i));\n if (rotated.join('::') < best.join('::')) {\n best = rotated;\n }\n }\n\n return [...best];\n}\n\n/**\n * Record a cycle into the result set, deduplicating by canonical key.\n * Returns true if the cycle was new (added), false if duplicate.\n */\nfunction recordCyclePath(\n cycleKeys: Set<string>,\n cycles: string[][],\n path: ReadonlyArray<string>,\n): boolean {\n const normalized = normalizeCycle(path);\n if (normalized.length === 0) return false;\n\n const key = normalized.join('->');\n if (cycleKeys.has(key)) return false;\n\n cycleKeys.add(key);\n cycles.push(normalized);\n return true;\n}\n\ninterface SccResult {\n readonly components: ReadonlyArray<ReadonlyArray<string>>;\n}\n\n/**\n * Tarjan's SCC algorithm. Returns all strongly connected components.\n */\nfunction tarjanScc(graph: Map<string, ReadonlyArray<string>>): SccResult {\n let index = 0;\n const stack: string[] = [];\n const onStack = new Set<string>();\n const indices = new Map<string, number>();\n const lowlinks = new Map<string, number>();\n const components: string[][] = [];\n\n const strongConnect = (node: string): void => {\n indices.set(node, index);\n lowlinks.set(node, index);\n index += 1;\n\n stack.push(node);\n onStack.add(node);\n\n for (const next of graph.get(node) ?? []) {\n if (!indices.has(next)) {\n strongConnect(next);\n lowlinks.set(node, Math.min(lowlinks.get(node) ?? 0, lowlinks.get(next) ?? 0));\n } else if (onStack.has(next)) {\n lowlinks.set(node, Math.min(lowlinks.get(node) ?? 0, indices.get(next) ?? 0));\n }\n }\n\n if (lowlinks.get(node) === indices.get(node)) {\n const component: string[] = [];\n let current = '';\n do {\n current = stack.pop() ?? '';\n onStack.delete(current);\n component.push(current);\n } while (current !== node && stack.length > 0);\n components.push(component);\n }\n };\n\n for (const node of graph.keys()) {\n if (!indices.has(node)) {\n strongConnect(node);\n }\n }\n\n return { components };\n}\n\n/**\n * Johnson's elementary circuit algorithm.\n * Finds all elementary circuits within a single SCC sub-graph.\n */\nfunction johnsonCircuits(\n scc: ReadonlyArray<string>,\n adjacency: Map<string, ReadonlyArray<string>>,\n maxCircuits: number,\n): string[][] {\n const cycles: string[][] = [];\n const cycleKeys = new Set<string>();\n const nodes = [...scc].sort(compareStrings);\n\n const unblock = (node: string, blocked: Set<string>, blockMap: Map<string, Set<string>>): void => {\n blocked.delete(node);\n const blockedBy = blockMap.get(node);\n if (!blockedBy) return;\n for (const entry of blockedBy) {\n if (blocked.has(entry)) {\n unblock(entry, blocked, blockMap);\n }\n }\n blockedBy.clear();\n };\n\n for (let i = 0; i < nodes.length && cycles.length < maxCircuits; i++) {\n const start = nodes[i] ?? '';\n const allowed = new Set(nodes.slice(i));\n const blocked = new Set<string>();\n const blockMap = new Map<string, Set<string>>();\n const stack: string[] = [];\n\n const neighbors = (v: string): ReadonlyArray<string> =>\n (adjacency.get(v) ?? []).filter(e => allowed.has(e));\n\n const circuit = (node: string): boolean => {\n if (cycles.length >= maxCircuits) return true;\n\n let found = false;\n stack.push(node);\n blocked.add(node);\n\n for (const next of neighbors(node)) {\n if (cycles.length >= maxCircuits) break;\n\n if (next === start) {\n recordCyclePath(cycleKeys, cycles, stack.concat(start));\n found = true;\n } else if (!blocked.has(next)) {\n if (circuit(next)) {\n found = true;\n }\n }\n }\n\n if (found) {\n unblock(node, blocked, blockMap);\n } else {\n for (const next of neighbors(node)) {\n const set = blockMap.get(next) ?? new Set<string>();\n set.add(node);\n blockMap.set(next, set);\n }\n }\n\n stack.pop();\n return found;\n };\n\n circuit(start);\n }\n\n return cycles;\n}\n\n/**\n * Detect all elementary cycles using Tarjan SCC preprocessing + Johnson's circuits.\n */\nfunction detectCycles(\n adjacency: Map<string, ReadonlyArray<string>>,\n maxCycles: number,\n): string[][] {\n const { components } = tarjanScc(adjacency);\n const cycles: string[][] = [];\n const cycleKeys = new Set<string>();\n\n for (const component of components) {\n if (cycles.length >= maxCycles) break;\n\n if (component.length === 0) continue;\n\n if (component.length === 1) {\n const node = component[0] ?? '';\n const neighbors = adjacency.get(node) ?? [];\n if (neighbors.includes(node)) {\n recordCyclePath(cycleKeys, cycles, [node, node]);\n }\n continue;\n }\n\n const remaining = maxCycles - cycles.length;\n const circuits = johnsonCircuits(component, adjacency, remaining);\n\n for (const c of circuits) {\n if (cycles.length >= maxCycles) break;\n recordCyclePath(cycleKeys, cycles, c);\n }\n }\n\n return cycles;\n}\n",
|
|
47
|
-
"import { GildashError } from '../errors';\nimport { DependencyGraph } from '../search/dependency-graph';\nimport type { GildashContext } from './context';\nimport type { FanMetrics } from './types';\n\n/** Graph cache TTL — matches healthcheck interval so readers stay fresh. */\nexport const GRAPH_CACHE_TTL_MS = 15_000;\n\n/** Invalidate the cached DependencyGraph (called after every index run). */\nexport function invalidateGraphCache(ctx: GildashContext): void {\n ctx.graphCache = null;\n ctx.graphCacheKey = null;\n ctx.graphCacheBuiltAt = null;\n}\n\n/**\n * Return a cached or freshly-built DependencyGraph for the given project.\n * Builds once per key; subsequent calls with the same key return the cached instance.\n * TTL-based expiry ensures readers don't hold stale graphs indefinitely.\n */\nexport function getOrBuildGraph(ctx: GildashContext, project?: string): DependencyGraph {\n const key = project ?? '__cross__';\n\n // TTL-based invalidation for readers (who don't get onIndexed callbacks)\n if (ctx.graphCache && ctx.graphCacheBuiltAt !== null) {\n if (Date.now() - ctx.graphCacheBuiltAt > GRAPH_CACHE_TTL_MS) {\n ctx.graphCache = null;\n ctx.graphCacheKey = null;\n ctx.graphCacheBuiltAt = null;\n }\n }\n\n if (ctx.graphCache && ctx.graphCacheKey === key) {\n return ctx.graphCache;\n }\n const g = new DependencyGraph({\n relationRepo: ctx.relationRepo,\n project: project ?? ctx.defaultProject,\n additionalProjects: project ? undefined : ctx.boundaries?.map(b => b.project),\n });\n g.build();\n ctx.graphCache = g;\n ctx.graphCacheKey = key;\n ctx.graphCacheBuiltAt = Date.now();\n return g;\n}\n\n/** List the files that a given file directly imports. */\nexport function getDependencies(\n ctx: GildashContext,\n filePath: string,\n project?: string,\n limit = 10_000,\n): string[] {\n if (ctx.closed) throw new GildashError('closed', 'Gildash: instance is closed');\n try {\n return ctx.relationSearchFn({\n relationRepo: ctx.relationRepo,\n project: project ?? ctx.defaultProject,\n query: { srcFilePath: filePath, type: 'imports', project: project ?? ctx.defaultProject, limit },\n }).map(r => r.dstFilePath);\n } catch (e) {\n if (e instanceof GildashError) throw e;\n throw new GildashError('search', 'Gildash: getDependencies failed', { cause: e });\n }\n}\n\n/** List the files that directly import a given file. */\nexport function getDependents(\n ctx: GildashContext,\n filePath: string,\n project?: string,\n limit = 10_000,\n): string[] {\n if (ctx.closed) throw new GildashError('closed', 'Gildash: instance is closed');\n try {\n return ctx.relationSearchFn({\n relationRepo: ctx.relationRepo,\n project: project ?? ctx.defaultProject,\n query: { dstFilePath: filePath, type: 'imports', project: project ?? ctx.defaultProject, limit },\n }).map(r => r.srcFilePath);\n } catch (e) {\n if (e instanceof GildashError) throw e;\n throw new GildashError('search', 'Gildash: getDependents failed', { cause: e });\n }\n}\n\n/** Compute the full set of files transitively affected by changes. */\nexport async function getAffected(\n ctx: GildashContext,\n changedFiles: string[],\n project?: string,\n): Promise<string[]> {\n if (ctx.closed) throw new GildashError('closed', 'Gildash: instance is closed');\n try {\n const g = getOrBuildGraph(ctx, project);\n return g.getAffectedByChange(changedFiles);\n } catch (e) {\n if (e instanceof GildashError) throw e;\n throw new GildashError('search', 'Gildash: getAffected failed', { cause: e });\n }\n}\n\n/** Check whether the import graph contains a circular dependency. */\nexport async function hasCycle(\n ctx: GildashContext,\n project?: string,\n): Promise<boolean> {\n if (ctx.closed) throw new GildashError('closed', 'Gildash: instance is closed');\n try {\n const g = getOrBuildGraph(ctx, project);\n return g.hasCycle();\n } catch (e) {\n if (e instanceof GildashError) throw e;\n throw new GildashError('search', 'Gildash: hasCycle failed', { cause: e });\n }\n}\n\n/** Return the full import graph as an adjacency list. */\nexport async function getImportGraph(\n ctx: GildashContext,\n project?: string,\n): Promise<Map<string, string[]>> {\n if (ctx.closed) throw new GildashError('closed', 'Gildash: instance is closed');\n try {\n const g = getOrBuildGraph(ctx, project);\n return g.getAdjacencyList();\n } catch (e) {\n if (e instanceof GildashError) throw e;\n throw new GildashError('search', 'Gildash: getImportGraph failed', { cause: e });\n }\n}\n\n/** Return all files that `filePath` transitively imports (forward BFS). */\nexport async function getTransitiveDependencies(\n ctx: GildashContext,\n filePath: string,\n project?: string,\n): Promise<string[]> {\n if (ctx.closed) throw new GildashError('closed', 'Gildash: instance is closed');\n try {\n const g = getOrBuildGraph(ctx, project);\n return g.getTransitiveDependencies(filePath);\n } catch (e) {\n if (e instanceof GildashError) throw e;\n throw new GildashError('search', 'Gildash: getTransitiveDependencies failed', { cause: e });\n }\n}\n\n/** Return all cycle paths in the import graph. */\nexport async function getCyclePaths(\n ctx: GildashContext,\n project?: string,\n options?: { maxCycles?: number },\n): Promise<string[][]> {\n if (ctx.closed) throw new GildashError('closed', 'Gildash: instance is closed');\n try {\n const g = getOrBuildGraph(ctx, project);\n return g.getCyclePaths(options);\n } catch (e) {\n if (e instanceof GildashError) throw e;\n throw new GildashError('search', 'Gildash: getCyclePaths failed', { cause: e });\n }\n}\n\n/** Compute import-graph fan metrics (fan-in / fan-out) for a single file. */\nexport async function getFanMetrics(\n ctx: GildashContext,\n filePath: string,\n project?: string,\n): Promise<FanMetrics> {\n if (ctx.closed) throw new GildashError('closed', 'Gildash: instance is closed');\n try {\n const g = getOrBuildGraph(ctx, project);\n return {\n filePath,\n fanIn: g.getDependents(filePath).length,\n fanOut: g.getDependencies(filePath).length,\n };\n } catch (e) {\n if (e instanceof GildashError) throw e;\n throw new GildashError('search', 'Gildash: getFanMetrics failed', { cause: e });\n }\n}\n",
|
|
48
|
-
"import { isErr } from '@zipbul/result';\nimport type { ParsedFile } from '../parser/types';\nimport type { ParserOptions } from 'oxc-parser';\nimport { GildashError } from '../errors';\nimport type { GildashContext } from './context';\nimport type { BatchParseResult } from './types';\n\n/** Parse a TypeScript source string into an AST and cache the result. */\nexport function parseSource(\n ctx: GildashContext,\n filePath: string,\n sourceText: string,\n options?: ParserOptions,\n): ParsedFile {\n if (ctx.closed) throw new GildashError('closed', 'Gildash: instance is closed');\n const result = ctx.parseSourceFn(filePath, sourceText, options);\n if (isErr(result)) throw result.data;\n ctx.parseCache.set(filePath, result);\n return result;\n}\n\n/** Parse multiple files concurrently and return results with failure details. */\nexport async function batchParse(\n ctx: GildashContext,\n filePaths: string[],\n options?: ParserOptions,\n): Promise<BatchParseResult> {\n if (ctx.closed) throw new GildashError('closed', 'Gildash: instance is closed');\n const parsed = new Map<string, ParsedFile>();\n const failures: Array<{ filePath: string; error: Error }> = [];\n await Promise.all(\n filePaths.map(async (fp) => {\n try {\n const text = await ctx.readFileFn(fp);\n const result = ctx.parseSourceFn(fp, text, options);\n if (!isErr(result)) {\n parsed.set(fp, result as ParsedFile);\n } else {\n failures.push({ filePath: fp, error: result.data });\n }\n } catch (e) {\n failures.push({\n filePath: fp,\n error: e instanceof Error ? e : new Error(String(e)),\n });\n }\n }),\n );\n return { parsed, failures };\n}\n\n/** Retrieve a previously-parsed AST from the internal LRU cache. */\nexport function getParsedAst(\n ctx: GildashContext,\n filePath: string,\n): ParsedFile | undefined {\n if (ctx.closed) return undefined;\n return ctx.parseCache.get(filePath);\n}\n",
|
|
49
|
-
"import type { ParsedFile } from '../parser/types';\nimport type { ExtractedSymbol, CodeRelation } from '../extractor/types';\nimport { GildashError } from '../errors';\nimport type { GildashContext } from './context';\n\n/** Extract all symbol declarations from a previously parsed file. */\nexport function extractSymbols(\n ctx: GildashContext,\n parsed: ParsedFile,\n): ExtractedSymbol[] {\n if (ctx.closed) throw new GildashError('closed', 'Gildash: instance is closed');\n return ctx.extractSymbolsFn(parsed);\n}\n\n/** Extract inter-file relationships from a previously parsed file. */\nexport function extractRelations(\n ctx: GildashContext,\n parsed: ParsedFile,\n): CodeRelation[] {\n if (ctx.closed) throw new GildashError('closed', 'Gildash: instance is closed');\n return ctx.extractRelationsFn(\n parsed.program,\n parsed.filePath,\n ctx.tsconfigPaths ?? undefined,\n );\n}\n",
|
|
50
|
-
"import path from 'node:path';\nimport type { SymbolSearchQuery, SymbolSearchResult } from '../search/symbol-search';\nimport type { RelationSearchQuery } from '../search/relation-search';\nimport type { CodeRelation } from '../extractor/types';\nimport type { FileRecord } from '../store/repositories/file.repository';\nimport type { SymbolStats } from '../store/repositories/symbol.repository';\nimport { GildashError } from '../errors';\nimport type { GildashContext } from './context';\nimport type { FullSymbol, FileStats, ModuleInterface } from './types';\n\n/** Return aggregate symbol statistics for the given project. */\nexport function getStats(\n ctx: GildashContext,\n project?: string,\n): SymbolStats {\n if (ctx.closed) throw new GildashError('closed', 'Gildash: instance is closed');\n try {\n return ctx.symbolRepo.getStats(project ?? ctx.defaultProject);\n } catch (e) {\n if (e instanceof GildashError) throw e;\n throw new GildashError('store', 'Gildash: getStats failed', { cause: e });\n }\n}\n\n/** Search indexed symbols by name, kind, file path, or export status. */\nexport function searchSymbols(\n ctx: GildashContext,\n query: SymbolSearchQuery,\n): SymbolSearchResult[] {\n if (ctx.closed) throw new GildashError('closed', 'Gildash: instance is closed');\n try {\n return ctx.symbolSearchFn({ symbolRepo: ctx.symbolRepo, project: ctx.defaultProject, query });\n } catch (e) {\n if (e instanceof GildashError) throw e;\n throw new GildashError('search', 'Gildash: searchSymbols failed', { cause: e });\n }\n}\n\n/** Search indexed code relationships (imports, calls, extends, implements). */\nexport function searchRelations(\n ctx: GildashContext,\n query: RelationSearchQuery,\n): CodeRelation[] {\n if (ctx.closed) throw new GildashError('closed', 'Gildash: instance is closed');\n try {\n return ctx.relationSearchFn({ relationRepo: ctx.relationRepo, project: ctx.defaultProject, query });\n } catch (e) {\n if (e instanceof GildashError) throw e;\n throw new GildashError('search', 'Gildash: searchRelations failed', { cause: e });\n }\n}\n\n/** Search symbols across all projects (no project filter). */\nexport function searchAllSymbols(\n ctx: GildashContext,\n query: Omit<SymbolSearchQuery, 'project'> & { project?: string },\n): SymbolSearchResult[] {\n if (ctx.closed) throw new GildashError('closed', 'Gildash: instance is closed');\n try {\n return ctx.symbolSearchFn({ symbolRepo: ctx.symbolRepo, project: undefined, query });\n } catch (e) {\n if (e instanceof GildashError) throw e;\n throw new GildashError('search', 'Gildash: searchAllSymbols failed', { cause: e });\n }\n}\n\n/** Search relations across all projects (no project filter). */\nexport function searchAllRelations(\n ctx: GildashContext,\n query: RelationSearchQuery,\n): CodeRelation[] {\n if (ctx.closed) throw new GildashError('closed', 'Gildash: instance is closed');\n try {\n return ctx.relationSearchFn({ relationRepo: ctx.relationRepo, project: undefined, query });\n } catch (e) {\n if (e instanceof GildashError) throw e;\n throw new GildashError('search', 'Gildash: searchAllRelations failed', { cause: e });\n }\n}\n\n/** List all files indexed for a given project. */\nexport function listIndexedFiles(\n ctx: GildashContext,\n project?: string,\n): FileRecord[] {\n if (ctx.closed) throw new GildashError('closed', 'Gildash: instance is closed');\n try {\n return ctx.fileRepo.getAllFiles(project ?? ctx.defaultProject);\n } catch (e) {\n if (e instanceof GildashError) throw e;\n throw new GildashError('store', 'Gildash: listIndexedFiles failed', { cause: e });\n }\n}\n\n/** Get all intra-file relations for a given file. */\nexport function getInternalRelations(\n ctx: GildashContext,\n filePath: string,\n project?: string,\n): CodeRelation[] {\n if (ctx.closed) throw new GildashError('closed', 'Gildash: instance is closed');\n try {\n return ctx.relationSearchFn({\n relationRepo: ctx.relationRepo,\n project: project ?? ctx.defaultProject,\n query: { srcFilePath: filePath, dstFilePath: filePath, limit: 10_000 },\n });\n } catch (e) {\n if (e instanceof GildashError) throw e;\n throw new GildashError('search', 'Gildash: getInternalRelations failed', { cause: e });\n }\n}\n\n/** Retrieve full details for a named symbol in a specific file. */\nexport function getFullSymbol(\n ctx: GildashContext,\n symbolName: string,\n filePath: string,\n project?: string,\n): FullSymbol | null {\n if (ctx.closed) throw new GildashError('closed', 'Gildash: instance is closed');\n try {\n const effectiveProject = project ?? ctx.defaultProject;\n const results = ctx.symbolSearchFn({\n symbolRepo: ctx.symbolRepo,\n project: effectiveProject,\n query: { text: symbolName, exact: true, filePath, limit: 1 },\n });\n if (results.length === 0) {\n return null;\n }\n const sym = results[0]!;\n const d = sym.detail;\n const full: FullSymbol = {\n ...sym,\n members: Array.isArray(d.members) ? (d.members as FullSymbol['members']) : undefined,\n jsDoc: typeof d.jsDoc === 'string' ? d.jsDoc : undefined,\n parameters: typeof d.parameters === 'string' ? d.parameters : undefined,\n returnType: typeof d.returnType === 'string' ? d.returnType : undefined,\n heritage: Array.isArray(d.heritage) ? (d.heritage as string[]) : undefined,\n decorators: Array.isArray(d.decorators) ? (d.decorators as FullSymbol['decorators']) : undefined,\n typeParameters: typeof d.typeParameters === 'string' ? d.typeParameters : undefined,\n };\n if (ctx.semanticLayer) {\n try {\n const absPath = path.isAbsolute(filePath) ? filePath : path.resolve(ctx.projectRoot, filePath);\n const declPos = ctx.semanticLayer.lineColumnToPosition(\n absPath, sym.span.start.line, sym.span.start.column,\n );\n if (declPos !== null) {\n const pos = ctx.semanticLayer.findNamePosition(absPath, declPos, sym.name) ?? declPos;\n const resolvedType = ctx.semanticLayer.collectTypeAt(absPath, pos);\n if (resolvedType) {\n full.resolvedType = resolvedType;\n }\n }\n } catch {\n // semantic enrichment is best-effort — don't fail the whole call\n }\n }\n return full;\n } catch (e) {\n if (e instanceof GildashError) throw e;\n throw new GildashError('search', 'Gildash: getFullSymbol failed', { cause: e });\n }\n}\n\n/** Retrieve statistics for an indexed file. */\nexport function getFileStats(\n ctx: GildashContext,\n filePath: string,\n project?: string,\n): FileStats {\n if (ctx.closed) throw new GildashError('closed', 'Gildash: instance is closed');\n try {\n const effectiveProject = project ?? ctx.defaultProject;\n const fileRecord = ctx.fileRepo.getFile(effectiveProject, filePath);\n if (!fileRecord) {\n throw new GildashError('search', `Gildash: file '${filePath}' is not in the index`);\n }\n const symbols = ctx.symbolRepo.getFileSymbols(effectiveProject, filePath);\n const relations = ctx.relationRepo.getOutgoing(effectiveProject, filePath);\n return {\n filePath: fileRecord.filePath,\n lineCount: fileRecord.lineCount ?? 0,\n size: fileRecord.size,\n symbolCount: symbols.length,\n exportedSymbolCount: symbols.filter((s) => s.isExported).length,\n relationCount: relations.length,\n };\n } catch (e) {\n if (e instanceof GildashError) throw e;\n throw new GildashError('store', 'Gildash: getFileStats failed', { cause: e });\n }\n}\n\n/** Retrieve metadata for an indexed file. */\nexport function getFileInfo(\n ctx: GildashContext,\n filePath: string,\n project?: string,\n): FileRecord | null {\n if (ctx.closed) throw new GildashError('closed', 'Gildash: instance is closed');\n try {\n return ctx.fileRepo.getFile(project ?? ctx.defaultProject, filePath);\n } catch (e) {\n if (e instanceof GildashError) throw e;\n throw new GildashError('store', 'Gildash: getFileInfo failed', { cause: e });\n }\n}\n\n/** List all symbols declared in a specific file. */\nexport function getSymbolsByFile(\n ctx: GildashContext,\n filePath: string,\n project?: string,\n): SymbolSearchResult[] {\n return searchSymbols(ctx, { filePath, project: project ?? undefined, limit: 10_000 });\n}\n\n/** Return the public interface of a module. */\nexport function getModuleInterface(\n ctx: GildashContext,\n filePath: string,\n project?: string,\n): ModuleInterface {\n if (ctx.closed) throw new GildashError('closed', 'Gildash: instance is closed');\n try {\n const symbols = ctx.symbolSearchFn({\n symbolRepo: ctx.symbolRepo,\n project: project ?? ctx.defaultProject,\n query: { filePath, isExported: true },\n }) as SymbolSearchResult[];\n const exports = symbols.map((s) => ({\n name: s.name,\n kind: s.kind,\n parameters: (s.detail.parameters as string | undefined) ?? undefined,\n returnType: (s.detail.returnType as string | undefined) ?? undefined,\n jsDoc: (s.detail.jsDoc as string | undefined) ?? undefined,\n }));\n return { filePath, exports };\n } catch (e) {\n if (e instanceof GildashError) throw e;\n throw new GildashError('search', 'Gildash: getModuleInterface failed', { cause: e });\n }\n}\n",
|
|
51
|
-
"import path from 'node:path';\nimport type { SymbolSearchResult } from '../search/symbol-search';\nimport { GildashError } from '../errors';\nimport type { ResolvedType, SemanticReference, Implementation, SemanticModuleInterface } from '../semantic/types';\nimport type { GildashContext } from './context';\n\n/**\n * Look up a symbol's position for semantic queries.\n * Returns `null` when the symbol is not indexed or position cannot be resolved.\n */\nexport function resolveSymbolPosition(\n ctx: GildashContext,\n symbolName: string,\n filePath: string,\n project?: string,\n): { sym: SymbolSearchResult; position: number; absPath: string } | null {\n const effectiveProject = project ?? ctx.defaultProject;\n const results = ctx.symbolSearchFn({\n symbolRepo: ctx.symbolRepo,\n project: effectiveProject,\n query: { text: symbolName, exact: true, filePath, limit: 1 },\n });\n if (results.length === 0) return null;\n const sym = results[0]!;\n const absPath = path.isAbsolute(filePath) ? filePath : path.resolve(ctx.projectRoot, filePath);\n const declPos = ctx.semanticLayer!.lineColumnToPosition(\n absPath,\n sym.span.start.line,\n sym.span.start.column,\n );\n if (declPos === null) return null;\n const position = ctx.semanticLayer!.findNamePosition(absPath, declPos, sym.name) ?? declPos;\n return { sym, position, absPath };\n}\n\n/** Retrieve the resolved type of a symbol using the Semantic Layer. */\nexport function getResolvedType(\n ctx: GildashContext,\n symbolName: string,\n filePath: string,\n project?: string,\n): ResolvedType | null {\n if (ctx.closed) throw new GildashError('closed', 'Gildash: instance is closed');\n if (!ctx.semanticLayer) throw new GildashError('semantic', 'Gildash: semantic layer is not enabled');\n try {\n const resolved = resolveSymbolPosition(ctx, symbolName, filePath, project);\n if (!resolved) {\n return null;\n }\n return ctx.semanticLayer.collectTypeAt(resolved.absPath, resolved.position);\n } catch (e) {\n if (e instanceof GildashError) throw e;\n throw new GildashError('search', 'Gildash: getResolvedType failed', { cause: e });\n }\n}\n\n/** Find all semantic references to a symbol. */\nexport function getSemanticReferences(\n ctx: GildashContext,\n symbolName: string,\n filePath: string,\n project?: string,\n): SemanticReference[] {\n if (ctx.closed) throw new GildashError('closed', 'Gildash: instance is closed');\n if (!ctx.semanticLayer) throw new GildashError('semantic', 'Gildash: semantic layer is not enabled');\n try {\n const resolved = resolveSymbolPosition(ctx, symbolName, filePath, project);\n if (!resolved) {\n throw new GildashError('search', `Gildash: symbol '${symbolName}' not found in '${filePath}'`);\n }\n return ctx.semanticLayer.findReferences(resolved.absPath, resolved.position);\n } catch (e) {\n if (e instanceof GildashError) throw e;\n throw new GildashError('search', 'Gildash: getSemanticReferences failed', { cause: e });\n }\n}\n\n/** Find implementations of an interface/abstract class. */\nexport function getImplementations(\n ctx: GildashContext,\n symbolName: string,\n filePath: string,\n project?: string,\n): Implementation[] {\n if (ctx.closed) throw new GildashError('closed', 'Gildash: instance is closed');\n if (!ctx.semanticLayer) throw new GildashError('semantic', 'Gildash: semantic layer is not enabled');\n try {\n const resolved = resolveSymbolPosition(ctx, symbolName, filePath, project);\n if (!resolved) {\n throw new GildashError('search', `Gildash: symbol '${symbolName}' not found in '${filePath}'`);\n }\n return ctx.semanticLayer.findImplementations(resolved.absPath, resolved.position);\n } catch (e) {\n if (e instanceof GildashError) throw e;\n throw new GildashError('search', 'Gildash: getImplementations failed', { cause: e });\n }\n}\n\n/** Retrieve the semantic module interface — exported symbols with resolved types. */\nexport function getSemanticModuleInterface(\n ctx: GildashContext,\n filePath: string,\n): SemanticModuleInterface {\n if (ctx.closed) throw new GildashError('closed', 'Gildash: instance is closed');\n if (!ctx.semanticLayer) throw new GildashError('semantic', 'Gildash: semantic layer is not enabled');\n try {\n return ctx.semanticLayer.getModuleInterface(filePath);\n } catch (e) {\n if (e instanceof GildashError) throw e;\n throw new GildashError('search', 'Gildash: getSemanticModuleInterface failed', { cause: e });\n }\n}\n",
|
|
52
|
-
"import type { SymbolSearchResult } from '../search/symbol-search';\nimport type { CodeRelation } from '../extractor/types';\nimport type { IndexResult } from '../indexer/index-coordinator';\nimport type { FileChangeEvent } from '../watcher/types';\nimport type { PatternMatch } from '../search/pattern-search';\nimport { GildashError } from '../errors';\nimport type { GildashContext } from './context';\nimport type { SymbolDiff, ResolvedSymbol, HeritageNode } from './types';\nimport { invalidateGraphCache } from './graph-api';\n\n/** Compare two snapshots of symbol search results and return a structured diff. */\nexport function diffSymbols(\n before: SymbolSearchResult[],\n after: SymbolSearchResult[],\n): SymbolDiff {\n const beforeMap = new Map<string, SymbolSearchResult>(before.map(s => [`${s.name}::${s.filePath}`, s]));\n const afterMap = new Map<string, SymbolSearchResult>(after.map(s => [`${s.name}::${s.filePath}`, s]));\n const added: SymbolSearchResult[] = [];\n const removed: SymbolSearchResult[] = [];\n const modified: Array<{ before: SymbolSearchResult; after: SymbolSearchResult }> = [];\n for (const [key, afterSym] of afterMap) {\n const beforeSym = beforeMap.get(key);\n if (!beforeSym) {\n added.push(afterSym);\n } else if (beforeSym.fingerprint !== afterSym.fingerprint) {\n modified.push({ before: beforeSym, after: afterSym });\n }\n }\n for (const [key, beforeSym] of beforeMap) {\n if (!afterMap.has(key)) removed.push(beforeSym);\n }\n return { added, removed, modified };\n}\n\n/** Register a callback that fires after each indexing run completes. */\nexport function onIndexed(\n ctx: GildashContext,\n callback: (result: IndexResult) => void,\n): () => void {\n ctx.onIndexedCallbacks.add(callback);\n if (!ctx.coordinator) {\n return () => { ctx.onIndexedCallbacks.delete(callback); };\n }\n const unsubscribe = ctx.coordinator.onIndexed(callback);\n return () => {\n ctx.onIndexedCallbacks.delete(callback);\n unsubscribe();\n };\n}\n\n/** Trigger a full re-index of all tracked files. */\nexport async function reindex(\n ctx: GildashContext,\n): Promise<IndexResult> {\n if (ctx.closed) throw new GildashError('closed', 'Gildash: instance is closed');\n if (!ctx.coordinator) {\n throw new GildashError('closed', 'Gildash: reindex() is not available for readers');\n }\n try {\n const result = await ctx.coordinator.fullIndex();\n invalidateGraphCache(ctx);\n return result;\n } catch (e) {\n if (e instanceof GildashError) throw e;\n throw new GildashError('index', 'Gildash: reindex failed', { cause: e });\n }\n}\n\n/** Resolve the original definition location of a symbol by following its re-export chain. */\nexport function resolveSymbol(\n ctx: GildashContext,\n symbolName: string,\n filePath: string,\n project?: string,\n): ResolvedSymbol {\n if (ctx.closed) throw new GildashError('closed', 'Gildash: instance is closed');\n const effectiveProject = project ?? ctx.defaultProject;\n const visited = new Set<string>();\n const chain: Array<{ filePath: string; exportedAs: string }> = [];\n\n let currentName = symbolName;\n let currentFile = filePath;\n\n for (;;) {\n const key = `${currentFile}::${currentName}`;\n if (visited.has(key)) {\n return { originalName: currentName, originalFilePath: currentFile, reExportChain: chain, circular: true };\n }\n visited.add(key);\n\n const rels = ctx.relationSearchFn({\n relationRepo: ctx.relationRepo,\n project: effectiveProject,\n query: { type: 're-exports', srcFilePath: currentFile, limit: 500 },\n }) as CodeRelation[];\n\n let nextFile: string | undefined;\n let nextName: string | undefined;\n\n for (const rel of rels) {\n let specifiers: Array<{ local: string; exported: string }> | undefined;\n if (rel.metaJson) {\n try {\n const meta = JSON.parse(rel.metaJson) as Record<string, unknown>;\n if (Array.isArray(meta['specifiers'])) {\n specifiers = meta['specifiers'] as Array<{ local: string; exported: string }>;\n }\n } catch { /* ignore malformed metaJson */ }\n }\n if (!specifiers) continue;\n const match = specifiers.find((s) => s.exported === currentName);\n if (!match) continue;\n nextFile = rel.dstFilePath;\n nextName = match.local;\n break;\n }\n\n if (!nextFile || !nextName) {\n return { originalName: currentName, originalFilePath: currentFile, reExportChain: chain, circular: false };\n }\n\n chain.push({ filePath: currentFile, exportedAs: currentName });\n currentFile = nextFile;\n currentName = nextName;\n }\n}\n\n/** Register a callback that fires whenever a watched file changes. */\nexport function onFileChanged(\n ctx: GildashContext,\n callback: (event: FileChangeEvent) => void,\n): () => void {\n ctx.onFileChangedCallbacks.add(callback);\n return () => { ctx.onFileChangedCallbacks.delete(callback); };\n}\n\n/** Register a callback that fires on internal errors (e.g. healthcheck failures). */\nexport function onError(\n ctx: GildashContext,\n callback: (error: GildashError) => void,\n): () => void {\n ctx.onErrorCallbacks.add(callback);\n return () => { ctx.onErrorCallbacks.delete(callback); };\n}\n\n/** Register a callback that fires when the watcher role changes (reader → owner). */\nexport function onRoleChanged(\n ctx: GildashContext,\n callback: (newRole: 'owner' | 'reader') => void,\n): () => void {\n ctx.onRoleChangedCallbacks.add(callback);\n return () => { ctx.onRoleChangedCallbacks.delete(callback); };\n}\n\n/** Search for an AST structural pattern across indexed TypeScript files. */\nexport async function findPattern(\n ctx: GildashContext,\n pattern: string,\n opts?: { filePaths?: string[]; project?: string },\n): Promise<PatternMatch[]> {\n if (ctx.closed) throw new GildashError('closed', 'Gildash: instance is closed');\n try {\n const effectiveProject = opts?.project ?? ctx.defaultProject;\n const filePaths: string[] = opts?.filePaths\n ? opts.filePaths\n : ctx.fileRepo.getAllFiles(effectiveProject).map((f) => f.filePath);\n\n return await ctx.patternSearchFn({ pattern, filePaths });\n } catch (e) {\n if (e instanceof GildashError) throw e;\n throw new GildashError('search', 'Gildash: findPattern failed', { cause: e });\n }\n}\n\n/** Recursively traverse extends/implements relations to build a heritage tree. */\nexport async function getHeritageChain(\n ctx: GildashContext,\n symbolName: string,\n filePath: string,\n project?: string,\n): Promise<HeritageNode> {\n if (ctx.closed) throw new GildashError('closed', 'Gildash: instance is closed');\n try {\n const proj = project ?? ctx.defaultProject;\n const visited = new Set<string>();\n\n const buildNode = (symName: string, fp: string, kind?: 'extends' | 'implements'): HeritageNode => {\n const key = `${symName}::${fp}`;\n if (visited.has(key)) {\n return { symbolName: symName, filePath: fp, kind, children: [] };\n }\n visited.add(key);\n\n const rels = ctx.relationSearchFn({\n relationRepo: ctx.relationRepo,\n project: proj,\n query: { srcFilePath: fp, srcSymbolName: symName, limit: 1000 },\n }) as CodeRelation[];\n\n const heritageRels = rels.filter(\n (r): r is CodeRelation & { type: 'extends' | 'implements' } =>\n r.type === 'extends' || r.type === 'implements',\n );\n\n const children = heritageRels\n .filter((r) => r.dstSymbolName != null)\n .map((r) => buildNode(r.dstSymbolName!, r.dstFilePath, r.type));\n\n return { symbolName: symName, filePath: fp, kind, children };\n };\n\n return buildNode(symbolName, filePath);\n } catch (e) {\n if (e instanceof GildashError) throw e;\n throw new GildashError('search', 'Gildash: getHeritageChain failed', { cause: e });\n }\n}\n",
|
|
53
|
-
"import type { ParsedFile } from '../parser/types';\nimport type { ParserOptions } from 'oxc-parser';\nimport type { ExtractedSymbol, CodeRelation } from '../extractor/types';\nimport type { IndexResult } from '../indexer/index-coordinator';\nimport type { ProjectBoundary } from '../common/project-discovery';\nimport type { SymbolSearchQuery, SymbolSearchResult } from '../search/symbol-search';\nimport type { RelationSearchQuery } from '../search/relation-search';\nimport type { SymbolStats } from '../store/repositories/symbol.repository';\nimport type { FileRecord } from '../store/repositories/file.repository';\nimport type { PatternMatch } from '../search/pattern-search';\nimport type { ResolvedType, SemanticReference, Implementation, SemanticModuleInterface } from '../semantic/types';\nimport type { GildashContext } from './context';\nimport type { FileChangeEvent } from '../watcher/types';\nimport { GildashError } from '../errors';\nimport type {\n Logger,\n GildashOptions,\n SymbolDiff,\n ModuleInterface,\n HeritageNode,\n FullSymbol,\n FileStats,\n FanMetrics,\n ResolvedSymbol,\n BatchParseResult,\n} from './types';\nimport type { GildashInternalOptions } from './lifecycle';\nimport { initializeContext, closeContext } from './lifecycle';\nimport * as parseApi from './parse-api';\nimport * as extractApi from './extract-api';\nimport * as queryApi from './query-api';\nimport * as graphApi from './graph-api';\nimport * as semanticApi from './semantic-api';\nimport * as miscApi from './misc-api';\n\n// ─── Re-exports (public API) ───────────────────────────────────────\n\nexport type {\n Logger,\n GildashOptions,\n SymbolDiff,\n ModuleInterface,\n HeritageNode,\n FullSymbol,\n FileStats,\n FanMetrics,\n ResolvedSymbol,\n BatchParseResult,\n} from './types';\nexport type { GildashInternalOptions } from './lifecycle';\n\n// ─── Gildash Facade ─────────────────────────────────────────────────\n\n/**\n * Main entry point for gildash.\n *\n * `Gildash` indexes TypeScript source code into a local SQLite database,\n * watches for file changes, and provides search / dependency-graph queries.\n *\n * Every public method either returns a value directly or throws a\n * `GildashError` on failure. Use `try/catch` with `instanceof GildashError`\n * to handle errors.\n *\n * Create an instance with the static {@link Gildash.open} factory.\n * Always call {@link Gildash.close} when done to release resources.\n */\nexport class Gildash {\n /** Internal state — exposed for advanced testing only. */\n readonly _ctx: GildashContext;\n\n /** Absolute path to the indexed project root. */\n get projectRoot(): string { return this._ctx.projectRoot; }\n\n /** Current watcher role: `'owner'` (can reindex) or `'reader'` (read-only). */\n get role(): 'owner' | 'reader' { return this._ctx.role; }\n\n /** Discovered project boundaries within the project root. */\n get projects(): ProjectBoundary[] { return [...this._ctx.boundaries]; }\n\n private constructor(ctx: GildashContext) {\n this._ctx = ctx;\n }\n\n /**\n * Create and initialise a new `Gildash` instance.\n * @throws {GildashError} if initialization fails.\n */\n static async open(options: GildashOptions & GildashInternalOptions): Promise<Gildash> {\n const ctx = await initializeContext(options);\n return new Gildash(ctx);\n }\n\n /** Shut down the instance and release all resources. */\n async close(opts?: { cleanup?: boolean }): Promise<void> {\n return closeContext(this._ctx, opts);\n }\n\n // ─── Parse ──────────────────────────────────────────────────────\n\n parseSource(filePath: string, sourceText: string, options?: ParserOptions): ParsedFile {\n return parseApi.parseSource(this._ctx, filePath, sourceText, options);\n }\n\n async batchParse(filePaths: string[], options?: ParserOptions): Promise<BatchParseResult> {\n return parseApi.batchParse(this._ctx, filePaths, options);\n }\n\n getParsedAst(filePath: string): ParsedFile | undefined {\n return parseApi.getParsedAst(this._ctx, filePath);\n }\n\n // ─── Extract ────────────────────────────────────────────────────\n\n extractSymbols(parsed: ParsedFile): ExtractedSymbol[] {\n return extractApi.extractSymbols(this._ctx, parsed);\n }\n\n extractRelations(parsed: ParsedFile): CodeRelation[] {\n return extractApi.extractRelations(this._ctx, parsed);\n }\n\n // ─── Query ──────────────────────────────────────────────────────\n\n getStats(project?: string): SymbolStats {\n return queryApi.getStats(this._ctx, project);\n }\n\n searchSymbols(query: SymbolSearchQuery): SymbolSearchResult[] {\n return queryApi.searchSymbols(this._ctx, query);\n }\n\n searchRelations(query: RelationSearchQuery): CodeRelation[] {\n return queryApi.searchRelations(this._ctx, query);\n }\n\n searchAllSymbols(query: Omit<SymbolSearchQuery, 'project'> & { project?: string }): SymbolSearchResult[] {\n return queryApi.searchAllSymbols(this._ctx, query);\n }\n\n searchAllRelations(query: RelationSearchQuery): CodeRelation[] {\n return queryApi.searchAllRelations(this._ctx, query);\n }\n\n listIndexedFiles(project?: string): FileRecord[] {\n return queryApi.listIndexedFiles(this._ctx, project);\n }\n\n getInternalRelations(filePath: string, project?: string): CodeRelation[] {\n return queryApi.getInternalRelations(this._ctx, filePath, project);\n }\n\n getFullSymbol(symbolName: string, filePath: string, project?: string): FullSymbol | null {\n return queryApi.getFullSymbol(this._ctx, symbolName, filePath, project);\n }\n\n getFileStats(filePath: string, project?: string): FileStats {\n return queryApi.getFileStats(this._ctx, filePath, project);\n }\n\n getFileInfo(filePath: string, project?: string): FileRecord | null {\n return queryApi.getFileInfo(this._ctx, filePath, project);\n }\n\n getSymbolsByFile(filePath: string, project?: string): SymbolSearchResult[] {\n return queryApi.getSymbolsByFile(this._ctx, filePath, project);\n }\n\n getModuleInterface(filePath: string, project?: string): ModuleInterface {\n return queryApi.getModuleInterface(this._ctx, filePath, project);\n }\n\n // ─── Graph ──────────────────────────────────────────────────────\n\n getDependencies(filePath: string, project?: string, limit = 10_000): string[] {\n return graphApi.getDependencies(this._ctx, filePath, project, limit);\n }\n\n getDependents(filePath: string, project?: string, limit = 10_000): string[] {\n return graphApi.getDependents(this._ctx, filePath, project, limit);\n }\n\n async getAffected(changedFiles: string[], project?: string): Promise<string[]> {\n return graphApi.getAffected(this._ctx, changedFiles, project);\n }\n\n async hasCycle(project?: string): Promise<boolean> {\n return graphApi.hasCycle(this._ctx, project);\n }\n\n async getImportGraph(project?: string): Promise<Map<string, string[]>> {\n return graphApi.getImportGraph(this._ctx, project);\n }\n\n async getTransitiveDependencies(filePath: string, project?: string): Promise<string[]> {\n return graphApi.getTransitiveDependencies(this._ctx, filePath, project);\n }\n\n async getCyclePaths(project?: string, options?: { maxCycles?: number }): Promise<string[][]> {\n return graphApi.getCyclePaths(this._ctx, project, options);\n }\n\n async getFanMetrics(filePath: string, project?: string): Promise<FanMetrics> {\n return graphApi.getFanMetrics(this._ctx, filePath, project);\n }\n\n // ─── Semantic ───────────────────────────────────────────────────\n\n getResolvedType(symbolName: string, filePath: string, project?: string): ResolvedType | null {\n return semanticApi.getResolvedType(this._ctx, symbolName, filePath, project);\n }\n\n getSemanticReferences(symbolName: string, filePath: string, project?: string): SemanticReference[] {\n return semanticApi.getSemanticReferences(this._ctx, symbolName, filePath, project);\n }\n\n getImplementations(symbolName: string, filePath: string, project?: string): Implementation[] {\n return semanticApi.getImplementations(this._ctx, symbolName, filePath, project);\n }\n\n getSemanticModuleInterface(filePath: string): SemanticModuleInterface {\n return semanticApi.getSemanticModuleInterface(this._ctx, filePath);\n }\n\n // ─── Misc ───────────────────────────────────────────────────────\n\n diffSymbols(before: SymbolSearchResult[], after: SymbolSearchResult[]): SymbolDiff {\n return miscApi.diffSymbols(before, after);\n }\n\n onIndexed(callback: (result: IndexResult) => void): () => void {\n return miscApi.onIndexed(this._ctx, callback);\n }\n\n async reindex(): Promise<IndexResult> {\n return miscApi.reindex(this._ctx);\n }\n\n resolveSymbol(symbolName: string, filePath: string, project?: string): ResolvedSymbol {\n return miscApi.resolveSymbol(this._ctx, symbolName, filePath, project);\n }\n\n async findPattern(pattern: string, opts?: { filePaths?: string[]; project?: string }): Promise<PatternMatch[]> {\n return miscApi.findPattern(this._ctx, pattern, opts);\n }\n\n async getHeritageChain(symbolName: string, filePath: string, project?: string): Promise<HeritageNode> {\n return miscApi.getHeritageChain(this._ctx, symbolName, filePath, project);\n }\n\n onFileChanged(callback: (event: FileChangeEvent) => void): () => void {\n return miscApi.onFileChanged(this._ctx, callback);\n }\n\n onError(callback: (error: GildashError) => void): () => void {\n return miscApi.onError(this._ctx, callback);\n }\n\n onRoleChanged(callback: (newRole: 'owner' | 'reader') => void): () => void {\n return miscApi.onRoleChanged(this._ctx, callback);\n }\n}\n"
|
|
54
|
-
],
|
|
55
|
-
"mappings": "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",
|
|
56
|
-
"debugId": "540D489DF398012964756E2164756E21",
|
|
57
|
-
"names": []
|
|
58
|
-
}
|