@pharaoh-so/local-analyzer 0.1.0 → 0.1.1

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/analyzer.mjs CHANGED
@@ -27904,7 +27904,7 @@ function extractExportStatement(node2, source, functions, classes, imports, expo
27904
27904
  function extractImport(node2, imports) {
27905
27905
  let sourceNode = node2.childForFieldName("source");
27906
27906
  if (!sourceNode) return;
27907
- let source = sourceNode.text.replace(/['"]/g, ""), symbols2 = [], isDefault = !1, isNamespace = !1, aliases = [], isTypeOnly = node2.children.some((c) => c.type === "type");
27907
+ let source = sourceNode.text.replace(/['"]/g, ""), symbols2 = [], isDefault = !1, isNamespace = !1, aliases = [], isTypeOnly2 = node2.children.some((c) => c.type === "type");
27908
27908
  for (let child of node2.children)
27909
27909
  if (child.type === "import_clause") {
27910
27910
  for (let clauseChild of child.children)
@@ -27933,7 +27933,7 @@ function extractImport(node2, imports) {
27933
27933
  isDefault,
27934
27934
  isNamespace,
27935
27935
  line: node2.startPosition.row + 1,
27936
- ...isTypeOnly ? { isTypeOnly } : {},
27936
+ ...isTypeOnly2 ? { isTypeOnly: isTypeOnly2 } : {},
27937
27937
  ...aliases.length > 0 ? { aliases } : {}
27938
27938
  });
27939
27939
  }
@@ -28080,20 +28080,29 @@ function readDynamicImportCandidates(rootNode) {
28080
28080
  importPath,
28081
28081
  rootRelative: wrapper?.rootRelative ?? !1,
28082
28082
  line: importCallNode.startPosition.row + 1,
28083
- extracted
28083
+ extracted,
28084
+ ...extracted.names.length > 0 && moduleScopeBinding(importCallNode) && { moduleScope: !0 }
28084
28085
  });
28085
28086
  }
28086
28087
  return candidates;
28087
28088
  }
28089
+ function moduleScopeBinding(call) {
28090
+ let expression = call.parent, awaited = expression?.type === "array" ? expression.parent?.parent?.parent : expression;
28091
+ if (awaited?.type !== "await_expression" || awaited.parent?.type !== "variable_declarator")
28092
+ return !1;
28093
+ let scope = awaited.parent.parent?.parent;
28094
+ return scope?.type === "program" || scope?.type === "export_statement" && scope.parent?.type === "program";
28095
+ }
28088
28096
  function bindDynamicImportCandidates(candidates, filePath, resolveSpecifier2) {
28089
28097
  let sites = [];
28090
- for (let { importPath, rootRelative, line, extracted } of candidates) {
28098
+ for (let { importPath, rootRelative, line, extracted, moduleScope } of candidates) {
28091
28099
  let extensionPath = rootRelative && importPath ? extensionRootPath(importPath) : null, specifier = rootRelative ? extensionPath ? resolveSpecifier2(extensionPath, filePath, "extension-root") : void 0 : importPath && !importPath.startsWith(".") ? resolveSpecifier2(importPath, filePath) : void 0;
28092
28100
  specifier?.external || sites.push({
28093
28101
  importPath,
28094
28102
  resolvedTarget: importPath ? rootRelative ? specifier?.target ?? null : specifier ? specifier.target ?? null : resolveRelativeImport(filePath, importPath) : null,
28095
28103
  line,
28096
- extracted
28104
+ extracted,
28105
+ ...moduleScope && { moduleScope }
28097
28106
  });
28098
28107
  }
28099
28108
  return sites;
@@ -28176,7 +28185,7 @@ function resolveDynamicImportSites(sites, filePath, parsedFiles) {
28176
28185
  importLine: site.line
28177
28186
  });
28178
28187
  }
28179
- extracted.namespaceId && (symbols2.set(extracted.namespaceId, targetFile), extracted.namespaceMethods.length > 0 && imports.push({
28188
+ extracted.namespaceId && (symbols2.set(extracted.namespaceId, targetFile), renames.set(extracted.namespaceId, "*"), extracted.namespaceMethods.length > 0 && imports.push({
28180
28189
  fromFile: filePath,
28181
28190
  toFile: targetFile,
28182
28191
  symbols: extracted.namespaceMethods,
@@ -28476,6 +28485,11 @@ var ExportRegistry = class {
28476
28485
  let entry = this.files.get(filePath);
28477
28486
  entry && returnTypes.size > 0 && (entry.returnTypes = returnTypes);
28478
28487
  }
28488
+ /** Retain a file's explicit export bindings after releasing its syntax tree. */
28489
+ addNamedReExports(filePath, exports) {
28490
+ let entry = this.files.get(filePath);
28491
+ entry && (entry.namedReExports = exports);
28492
+ }
28479
28493
  /**
28480
28494
  * Get the set of all file paths stored in the registry across all chunks.
28481
28495
  *
@@ -28586,7 +28600,7 @@ var ExportRegistry = class {
28586
28600
  importLine: item.importLine
28587
28601
  });
28588
28602
  }
28589
- item.namespaceId && (entry.symbols.has(item.namespaceId) || entry.symbols.set(item.namespaceId, targetFile), item.namespaceMethods.length > 0 && entry.imports.push({
28603
+ item.namespaceId && (entry.symbols.has(item.namespaceId) || (entry.symbols.set(item.namespaceId, targetFile), entry.renames.set(item.namespaceId, "*")), item.namespaceMethods.length > 0 && entry.imports.push({
28590
28604
  fromFile: filePath,
28591
28605
  toFile: targetFile,
28592
28606
  symbols: item.namespaceMethods,
@@ -28775,6 +28789,237 @@ function starExportTargets(fileImports) {
28775
28789
  return targets;
28776
28790
  }
28777
28791
 
28792
+ // src/resolver/re-exports.ts
28793
+ function isTypeOnly(node2) {
28794
+ return node2.children.some(
28795
+ (child) => child.type === "type" || child.type === "ERROR" && child.text === "type"
28796
+ );
28797
+ }
28798
+ function moduleSpecifier(node2) {
28799
+ return node2.childForFieldName("source")?.text.slice(1, -1);
28800
+ }
28801
+ function nonCallableBinding(file, name = "*") {
28802
+ return { file, name, local: !0 };
28803
+ }
28804
+ function importedBindings(root2, file, names, resolveSpecifier2, dynamicSites, knownFiles) {
28805
+ let bindings = /* @__PURE__ */ new Map(), add = (local, binding2) => {
28806
+ names.has(local) && bindings.set(local, bindings.has(local) ? null : binding2);
28807
+ };
28808
+ for (let statement of root2.namedChildren) {
28809
+ if (statement.type !== "import_statement") continue;
28810
+ let source = moduleSpecifier(statement), clause = statement.namedChildren.find((child) => child.type === "import_clause");
28811
+ if (source === void 0 || !clause) continue;
28812
+ let typeOnly = isTypeOnly(statement), resolution, bind = (local, original, typeOnly2, namespace2 = !1) => {
28813
+ if (!names.has(local)) return;
28814
+ if (typeOnly2) {
28815
+ add(local, null);
28816
+ return;
28817
+ }
28818
+ resolution ??= resolveSpecifier2(source, file, void 0, statement.startPosition.row + 1);
28819
+ let target = resolution.target;
28820
+ add(
28821
+ local,
28822
+ target ? namespace2 ? nonCallableBinding(target) : { file: target, name: original } : nonCallableBinding(file, `*:${local}`)
28823
+ );
28824
+ };
28825
+ for (let child of clause.namedChildren) {
28826
+ if (child.type === "identifier" && bind(child.text, "default", typeOnly), child.type === "namespace_import") {
28827
+ let name = child.namedChildren.find((member) => member.type === "identifier")?.text;
28828
+ name && bind(name, "*", typeOnly, !0);
28829
+ }
28830
+ if (child.type === "named_imports")
28831
+ for (let specifier of child.namedChildren) {
28832
+ let name = specifier.childForFieldName("name")?.text, alias = specifier.childForFieldName("alias")?.text;
28833
+ name && bind(alias ?? name, name, typeOnly || isTypeOnly(specifier));
28834
+ }
28835
+ }
28836
+ }
28837
+ for (let site of dynamicSites) {
28838
+ if (!site.moduleScope || !site.extracted.names.some(({ local }) => names.has(local))) continue;
28839
+ let target = site.resolvedTarget && knownFiles && findParsedFilePath(knownFiles, site.resolvedTarget);
28840
+ for (let { local, original } of site.extracted.names)
28841
+ add(
28842
+ local,
28843
+ target ? { file: target, name: original } : nonCallableBinding(file, `*:${local}`)
28844
+ );
28845
+ }
28846
+ return bindings;
28847
+ }
28848
+ var CALLABLE_DECLARATIONS = /* @__PURE__ */ new Set([
28849
+ "function_declaration",
28850
+ "generator_function_declaration",
28851
+ "class_declaration",
28852
+ "abstract_class_declaration"
28853
+ ]), CALLABLE_EXPRESSIONS = /* @__PURE__ */ new Set([
28854
+ "arrow_function",
28855
+ "function_expression",
28856
+ "generator_function",
28857
+ "class"
28858
+ ]);
28859
+ function recordPattern(node2, record2) {
28860
+ if (node2.type === "identifier" || node2.type === "shorthand_property_identifier_pattern") {
28861
+ record2(node2.text);
28862
+ return;
28863
+ }
28864
+ if (node2.type === "pair_pattern" || node2.type === "assignment_pattern" || node2.type === "object_assignment_pattern") {
28865
+ let value = node2.childForFieldName(node2.type === "pair_pattern" ? "value" : "left");
28866
+ value && recordPattern(value, record2);
28867
+ return;
28868
+ }
28869
+ for (let child of node2.namedChildren) recordPattern(child, record2);
28870
+ }
28871
+ function recordDeclaration(node2, record2) {
28872
+ if (node2.type === "lexical_declaration" || node2.type === "variable_declaration") {
28873
+ for (let declarator of node2.namedChildren) {
28874
+ if (declarator.type !== "variable_declarator") continue;
28875
+ let pattern = declarator.childForFieldName("name"), value = declarator.childForFieldName("value");
28876
+ pattern && recordPattern(pattern, (name2) => record2(name2, CALLABLE_EXPRESSIONS.has(value?.type ?? "")));
28877
+ }
28878
+ return;
28879
+ }
28880
+ let callable = CALLABLE_DECLARATIONS.has(node2.type);
28881
+ if (!callable && node2.type !== "enum_declaration" && node2.type !== "internal_module") return;
28882
+ let name = node2.childForFieldName("name");
28883
+ name && record2(name.text, callable);
28884
+ }
28885
+ function commonJsAssignment(statement) {
28886
+ if (statement.type !== "expression_statement") return !1;
28887
+ let expression = statement.namedChildren[0];
28888
+ if (expression?.type !== "assignment_expression") return !1;
28889
+ let left = expression.childForFieldName("left");
28890
+ return !!left && /^(?:module\.exports|exports)(?:\.|\[|$)/.test(left.text);
28891
+ }
28892
+ function readNamedReExports(root2, file, resolveSpecifier2, dynamicSites = [], parsedExports = [], knownFiles) {
28893
+ let named = /* @__PURE__ */ new Map(), stars = /* @__PURE__ */ new Set(), localValues = /* @__PURE__ */ new Set(), callable = /* @__PURE__ */ new Set(), types2 = /* @__PURE__ */ new Set(), localExports = [], commonJs = !1, hasExportStatement = !1, local = (name) => ({ file, name, local: !0, topLevel: !0 }), recordLocal = (name, isCallable) => {
28894
+ localValues.add(name), isCallable && callable.add(name);
28895
+ }, addNamed = (name, binding2) => named.set(name, named.has(name) ? null : binding2);
28896
+ for (let statement of root2.namedChildren) {
28897
+ if (statement.type !== "export_statement") {
28898
+ recordDeclaration(statement, recordLocal), commonJs || (commonJs = commonJsAssignment(statement));
28899
+ continue;
28900
+ }
28901
+ hasExportStatement = !0;
28902
+ let source = moduleSpecifier(statement), typeOnly = isTypeOnly(statement), clause = statement.namedChildren.find((child) => child.type === "export_clause");
28903
+ if (clause) {
28904
+ let target = source !== void 0 && !typeOnly ? resolveSpecifier2(source, file, void 0, statement.startPosition.row + 1).target : void 0;
28905
+ for (let specifier of clause.namedChildren) {
28906
+ let original = specifier.childForFieldName("name")?.text;
28907
+ if (!original) continue;
28908
+ let name = specifier.childForFieldName("alias")?.text ?? original;
28909
+ typeOnly || isTypeOnly(specifier) ? types2.add(name) : source === void 0 ? localExports.push({ name, original }) : addNamed(
28910
+ name,
28911
+ target ? { file: target, name: original } : nonCallableBinding(file, `*:${name}`)
28912
+ );
28913
+ }
28914
+ continue;
28915
+ }
28916
+ if (typeOnly) continue;
28917
+ if (source !== void 0) {
28918
+ if (statement.children.some((child) => child.type === "*")) {
28919
+ let target = resolveSpecifier2(
28920
+ source,
28921
+ file,
28922
+ void 0,
28923
+ statement.startPosition.row + 1
28924
+ ).target;
28925
+ target && stars.add(target);
28926
+ } else {
28927
+ let name = statement.namedChildren.find(
28928
+ (child) => child.type === "namespace_export"
28929
+ )?.namedChildren[0]?.text;
28930
+ if (name) {
28931
+ let target = resolveSpecifier2(
28932
+ source,
28933
+ file,
28934
+ void 0,
28935
+ statement.startPosition.row + 1
28936
+ ).target;
28937
+ addNamed(
28938
+ name,
28939
+ target ? nonCallableBinding(target) : nonCallableBinding(file, `*:${name}`)
28940
+ );
28941
+ }
28942
+ }
28943
+ continue;
28944
+ }
28945
+ let isDefault = statement.children.some((child) => child.type === "default"), declaration2 = statement.childForFieldName("declaration"), value = statement.childForFieldName("value");
28946
+ if (declaration2)
28947
+ recordDeclaration(declaration2, (name, isCallable) => {
28948
+ recordLocal(name, isCallable), addNamed(isDefault ? "default" : name, local(name));
28949
+ });
28950
+ else if (isDefault && value?.type === "identifier")
28951
+ localExports.push({ name: "default", original: value.text });
28952
+ else if (isDefault) {
28953
+ let name = parsedExports.find((entry) => entry.isDefault)?.name ?? "default";
28954
+ recordLocal(name, CALLABLE_EXPRESSIONS.has(value?.type ?? "")), addNamed("default", local(name));
28955
+ }
28956
+ }
28957
+ if (localExports.length > 0) {
28958
+ let names = new Set(localExports.map(({ original }) => original)), imported = importedBindings(
28959
+ root2,
28960
+ file,
28961
+ names,
28962
+ resolveSpecifier2,
28963
+ dynamicSites,
28964
+ knownFiles
28965
+ );
28966
+ for (let { name, original } of localExports) {
28967
+ let binding2 = imported.get(original);
28968
+ addNamed(
28969
+ name,
28970
+ binding2 === void 0 ? localValues.has(original) ? local(original) : null : binding2
28971
+ );
28972
+ }
28973
+ }
28974
+ for (let name of types2) named.has(name) || named.set(name, null);
28975
+ return {
28976
+ named,
28977
+ stars: [...stars],
28978
+ callable,
28979
+ ...commonJs && !hasExportStatement && { commonJs: !0 }
28980
+ };
28981
+ }
28982
+ var MAX_EXPORT_STATES = 4096;
28983
+ function createImportedSymbolResolver(imports, functions, reExports, defaultName, onExhausted) {
28984
+ return (startFile, startName) => {
28985
+ let start = reExports(startFile), binding2 = start?.named.get(startName);
28986
+ if (binding2 === null) return;
28987
+ if (binding2?.local)
28988
+ return start?.callable.has(binding2.name) && functions.get(startFile)?.has(binding2.name) ? { file: startFile, name: binding2.name, topLevel: !0 } : void 0;
28989
+ if (!binding2 && !start?.stars.length && functions.get(startFile)?.has(startName))
28990
+ return { file: startFile, name: startName };
28991
+ let queue2 = [{ file: startFile, name: startName }], visited = /* @__PURE__ */ new Map([[startFile, /* @__PURE__ */ new Set([startName])]]), enqueue = (file, name) => {
28992
+ let names = visited.get(file) ?? /* @__PURE__ */ new Set();
28993
+ return names.has(name) ? !0 : queue2.length >= MAX_EXPORT_STATES ? (onExhausted?.(startFile), !1) : (names.add(name), visited.set(file, names), queue2.push({ file, name }), !0);
28994
+ }, result2;
28995
+ for (let index = 0; index < queue2.length; index++) {
28996
+ let { file, name } = queue2[index], facts = reExports(file), explicit = facts?.named.get(name), declaration2;
28997
+ if (explicit !== null) {
28998
+ if (explicit?.local)
28999
+ declaration2 = { file: explicit.file, name: explicit.name, topLevel: !0 };
29000
+ else if (explicit) {
29001
+ if (!enqueue(explicit.file, explicit.name)) return;
29002
+ } else {
29003
+ let legacy = !facts || facts.commonJs || index === 0, actualName = name === "default" ? defaultName(file) ?? name : name;
29004
+ if (legacy && functions.get(file)?.has(actualName) && !facts?.stars.length)
29005
+ declaration2 = { file, name: actualName };
29006
+ else if (name !== "default") {
29007
+ let fileImports = imports.get(file), named = fileImports?.get(name), targets = facts && !facts.commonJs ? facts.stars : named ? [named] : starExportTargets(fileImports);
29008
+ for (let target of targets) if (!enqueue(target, name)) return;
29009
+ }
29010
+ }
29011
+ if (declaration2) {
29012
+ if (result2 && (result2.file !== declaration2.file || result2.name !== declaration2.name))
29013
+ return;
29014
+ result2 = declaration2;
29015
+ }
29016
+ }
29017
+ }
29018
+ if (!(!result2 || !functions.get(result2.file)?.has(result2.name)) && !(result2.topLevel && !reExports(result2.file)?.callable.has(result2.name)))
29019
+ return result2;
29020
+ };
29021
+ }
29022
+
28778
29023
  // src/resolver/router-registration.ts
28779
29024
  var ROUTER_PACKAGES = /* @__PURE__ */ new Set([
28780
29025
  "express",
@@ -28899,6 +29144,7 @@ function resolveRegistryImports(registry, fileIndex, tsConfig, opts) {
28899
29144
  stats.resolved++, resolved.push({
28900
29145
  fromFile: filePath,
28901
29146
  toFile: target,
29147
+ source: imp.source,
28902
29148
  symbols: imp.symbols,
28903
29149
  isTypeOnly: imp.isTypeOnly,
28904
29150
  importLine: imp.line,
@@ -29280,7 +29526,7 @@ var tsParser2 = new Parser();
29280
29526
  tsParser2.setLanguage(tsLanguage);
29281
29527
  var tsxParser2 = new Parser();
29282
29528
  tsxParser2.setLanguage(tsxLanguage);
29283
- var pyParser2 = new Parser();
29529
+ var jsParser = tsxLanguage === tsxLanguage ? tsxParser2 : new Parser().setLanguage(tsxLanguage), pyParser2 = new Parser();
29284
29530
  pyParser2.setLanguage(pyLanguage);
29285
29531
  var BUILT_INS = /* @__PURE__ */ new Set([
29286
29532
  "console",
@@ -29473,27 +29719,39 @@ function classifyCallContext(callNode) {
29473
29719
  }
29474
29720
  return "production";
29475
29721
  }
29476
- function resolveReExport(symbolName, immediateTarget, importSymbolMap, fileFunctionNames) {
29477
- let queue2 = [immediateTarget], visited = /* @__PURE__ */ new Set();
29478
- for (let currentFile = queue2.shift(); currentFile; currentFile = queue2.shift()) {
29479
- if (visited.has(currentFile)) continue;
29480
- visited.add(currentFile);
29481
- let fileImports = importSymbolMap.get(currentFile), named = fileImports?.get(symbolName);
29482
- for (let nextFile of named ? [named] : starExportTargets(fileImports)) {
29483
- if (fileFunctionNames.get(nextFile)?.has(symbolName)) return nextFile;
29484
- queue2.push(nextFile);
29485
- }
29722
+ function resolvedFunctionUid(repoName, target, classNames) {
29723
+ return target ? buildFunctionUid(repoName, target.file, {
29724
+ name: target.name,
29725
+ className: target.topLevel ? void 0 : classNames.get(target.file)?.get(target.name)
29726
+ }) : void 0;
29727
+ }
29728
+ function namespaceBindings(imports) {
29729
+ let names = /* @__PURE__ */ new Set();
29730
+ for (let statement of imports) {
29731
+ if (!statement.isNamespace || statement.isTypeOnly) continue;
29732
+ let name = statement.symbols.at(-1);
29733
+ name && name !== "*" && names.add(name);
29486
29734
  }
29487
- return null;
29735
+ return names;
29488
29736
  }
29489
- function memberTarget(name, member, targetFile, importSymbolMap, fileFunctionNames, instanceClasses, hasMember) {
29490
- let [className2, classFrom] = instanceClassOf(
29491
- name,
29492
- targetFile,
29493
- importSymbolMap,
29494
- instanceClasses
29495
- ) ?? [name, targetFile], file = fileFunctionNames.get(classFrom)?.has(className2) ? classFrom : resolveReExport(className2, classFrom, importSymbolMap, fileFunctionNames);
29496
- return file && hasMember(file, `${className2}.${member}`) ? { file, className: className2 } : void 0;
29737
+ function isPythonModuleReceiver(file, binding2, functions) {
29738
+ return file.endsWith(".py") && pythonModuleName(file) === binding2 && !functions.get(file)?.has(binding2);
29739
+ }
29740
+ function functionReceiverMember(member) {
29741
+ return member === "call" || member === "apply" || member === "bind";
29742
+ }
29743
+ function pythonFactoryReceiverUid(repo, classes, file, name) {
29744
+ return file.endsWith(".py") && classes.byName.get(name)?.some((cls) => cls.file === file) ? buildFunctionUid(repo, file, { name }) : void 0;
29745
+ }
29746
+ function memberTarget(name, member, targetFile, importSymbolMap, aliases, resolveImported, instanceClasses, hasMember) {
29747
+ let instance = instanceClassOf(name, targetFile, importSymbolMap, instanceClasses), target;
29748
+ if (instance) {
29749
+ let [className2, file] = instance;
29750
+ if (hasMember(file, `${className2}.${member}`)) return { file, className: className2 };
29751
+ let imported = importSymbolMap.get(file)?.get(className2);
29752
+ imported && (target = resolveImported(imported, aliases.get(file)?.get(className2) ?? className2));
29753
+ } else target = resolveImported(targetFile, name);
29754
+ return target && hasMember(target.file, `${target.name}.${member}`) ? { file: target.file, className: target.name } : void 0;
29497
29755
  }
29498
29756
  function instanceClassOf(name, file, importSymbolMap, instanceClasses) {
29499
29757
  let visited = /* @__PURE__ */ new Set(), current = file;
@@ -29956,7 +30214,15 @@ function traceCallChainsFromRegistry(registry, importSymbolMap, repoName, aliasM
29956
30214
  let fnMap = fileFnClassNames.get(path5);
29957
30215
  fnMap || (fnMap = /* @__PURE__ */ new Map(), fileFnClassNames.set(path5, fnMap)), fnMap.set(fn.name, fn.className);
29958
30216
  }
29959
- let effectiveAliasMap = aliasMap ?? /* @__PURE__ */ new Map(), instanceClasses = /* @__PURE__ */ new Map();
30217
+ let effectiveAliasMap = aliasMap ?? /* @__PURE__ */ new Map(), namespaceNames = new Map(
30218
+ [...registry.entries()].map(([file, entry]) => [file, namespaceBindings(entry.imports)])
30219
+ ), exhausted = /* @__PURE__ */ new Set(), tracingFile, resolveImported = createImportedSymbolResolver(
30220
+ importSymbolMap,
30221
+ fileFunctionNames,
30222
+ (file) => registry.getFileEntry(file)?.namedReExports,
30223
+ (file) => registry.getFileEntry(file)?.defaultExportName,
30224
+ (file) => exhausted.add(tracingFile ?? file)
30225
+ ), instanceClasses = /* @__PURE__ */ new Map();
29960
30226
  for (let [path5, entry] of registry.entries())
29961
30227
  entry.instanceClasses && instanceClasses.set(path5, new Map(Object.entries(entry.instanceClasses)));
29962
30228
  let classMembers = /* @__PURE__ */ new Map();
@@ -29968,6 +30234,7 @@ function traceCallChainsFromRegistry(registry, importSymbolMap, repoName, aliasM
29968
30234
  importSymbolMap,
29969
30235
  aliasMap: effectiveAliasMap,
29970
30236
  fileFunctionNames,
30237
+ resolveImported,
29971
30238
  classes: buildClassIndex([...registry.entries()].map(([, entry]) => entry)),
29972
30239
  hasMember: (file, classMember) => classMembers.get(file)?.has(classMember) ?? !1,
29973
30240
  returnTypes: (file) => registry.getFileEntry(file)?.returnTypes,
@@ -29976,29 +30243,28 @@ function traceCallChainsFromRegistry(registry, importSymbolMap, repoName, aliasM
29976
30243
  }, resolveReceiverCall = (call, filePath) => {
29977
30244
  if (!call.receiver) return;
29978
30245
  let receiverFile = importSymbolMap.get(filePath)?.get(call.receiver);
29979
- if (receiverFile) {
29980
- let target = memberTarget(
29981
- effectiveAliasMap.get(filePath)?.get(call.receiver) ?? call.receiver,
29982
- call.calledName,
29983
- receiverFile,
29984
- importSymbolMap,
29985
- fileFunctionNames,
29986
- instanceClasses,
29987
- (f, key) => registry.getFileEntry(f)?.functions.some((fn) => `${fn.className}.${fn.name}` === key)
30246
+ if (!receiverFile) return;
30247
+ let alias = effectiveAliasMap.get(filePath)?.get(call.receiver);
30248
+ if (alias === "*" || namespaceNames.get(filePath)?.has(call.receiver) || isPythonModuleReceiver(receiverFile, alias ?? call.receiver, fileFunctionNames))
30249
+ return resolvedFunctionUid(
30250
+ repoName,
30251
+ resolveImported(receiverFile, call.calledName),
30252
+ fileFnClassNames
29988
30253
  );
29989
- if (target)
29990
- return buildFunctionUid(repoName, target.file, {
29991
- name: call.calledName,
29992
- className: target.className
29993
- });
29994
- }
29995
- let names = receiverFile ? fileFunctionNames.get(receiverFile) : void 0;
29996
- if (!receiverFile || !names) return;
29997
- let name = names.has(call.calledName) ? call.calledName : names.has(call.receiver) ? call.receiver : void 0;
29998
- return name ? buildFunctionUid(repoName, receiverFile, {
30254
+ let name = alias ?? call.receiver, target = memberTarget(
29999
30255
  name,
30000
- className: fileFnClassNames.get(receiverFile)?.get(name)
30001
- }) : void 0;
30256
+ call.calledName,
30257
+ receiverFile,
30258
+ importSymbolMap,
30259
+ effectiveAliasMap,
30260
+ resolveImported,
30261
+ instanceClasses,
30262
+ (f, key) => classMembers.get(f)?.has(key)
30263
+ );
30264
+ return target ? buildFunctionUid(repoName, target.file, {
30265
+ name: call.calledName,
30266
+ className: target.className
30267
+ }) : pythonFactoryReceiverUid(repoName, typedContext.classes, receiverFile, name) ?? (functionReceiverMember(call.calledName) ? resolvedFunctionUid(repoName, resolveImported(receiverFile, name), fileFnClassNames) : void 0);
30002
30268
  };
30003
30269
  registry.resolvePendingDynamicImports();
30004
30270
  let registryDynamicImports = [], perFileDynImportCounts = /* @__PURE__ */ new Map();
@@ -30043,15 +30309,11 @@ function traceCallChainsFromRegistry(registry, importSymbolMap, repoName, aliasM
30043
30309
  }
30044
30310
  let viaReceiver = resolveReceiverCall(call, filePath);
30045
30311
  if (viaReceiver) return [viaReceiver];
30312
+ if (call.receiver && importSymbolMap.get(filePath)?.has(call.receiver)) return [];
30046
30313
  let targetFile = !!call.receiver && isSelfReceiver(call.receiver) ? void 0 : importSymbolMap.get(filePath)?.get(calledName);
30047
30314
  if (targetFile) {
30048
- let originalName = effectiveAliasMap.get(filePath)?.get(calledName) ?? calledName, definingFile = fileFunctionNames.get(targetFile)?.has(originalName) ? targetFile : resolveReExport(originalName, targetFile, importSymbolMap, fileFunctionNames);
30049
- return definingFile ? [
30050
- buildFunctionUid(repoName, definingFile, {
30051
- name: originalName,
30052
- className: fileFnClassNames.get(definingFile)?.get(originalName)
30053
- })
30054
- ] : [];
30315
+ let originalName = effectiveAliasMap.get(filePath)?.get(calledName) ?? calledName, target = resolveImported(targetFile, originalName), uid = resolvedFunctionUid(repoName, target, fileFnClassNames);
30316
+ return uid ? [uid] : [];
30055
30317
  }
30056
30318
  return calledName !== callerName && fileFunctionNames.get(filePath)?.has(calledName) ? [
30057
30319
  buildFunctionUid(repoName, filePath, {
@@ -30073,8 +30335,10 @@ function traceCallChainsFromRegistry(registry, importSymbolMap, repoName, aliasM
30073
30335
  });
30074
30336
  callerName.startsWith("$module_init") && resolved.length > resolvedBefore && !topLevelCallerUids.includes(callerUid) && topLevelCallerUids.push(callerUid);
30075
30337
  };
30076
- for (let [filePath, entry] of registry.entries())
30338
+ for (let [filePath, entry] of registry.entries()) {
30339
+ tracingFile = filePath;
30077
30340
  for (let fn of entry.functions) resolveCallsOf(fn.uid, fn.name, filePath, fn.calls);
30341
+ }
30078
30342
  for (let [callerUid, calls] of registry.getAllCallSites()) {
30079
30343
  let firstColon = callerUid.indexOf(":"), lastColon = callerUid.lastIndexOf(":");
30080
30344
  if (firstColon < 0 || lastColon <= firstColon) continue;
@@ -30088,8 +30352,8 @@ function traceCallChainsFromRegistry(registry, importSymbolMap, repoName, aliasM
30088
30352
  dynamicImports: registryDynamicImports,
30089
30353
  topLevelCallerUids,
30090
30354
  perFileDynImportCounts,
30091
- untraced: []
30092
- // it parses nothing: the chunked pipeline adds the files it couldn't trace
30355
+ untraced: [...exhausted]
30356
+ // the chunked pipeline adds files it could not parse or read
30093
30357
  };
30094
30358
  }
30095
30359
  function referenceSites(node2, callerName, skip) {
@@ -30421,8 +30685,8 @@ function declaredClass(ctx, typeName, filePath, reachable) {
30421
30685
  if (name = typeName.slice(dot + 1), !(module && pythonModuleName(module) === head && !ctx.fileFunctionNames.get(module)?.has(head)) || name.includes(".")) return;
30422
30686
  typeFile = module;
30423
30687
  }
30424
- let named = (ctx.classes.byName.get(name) ?? []).filter(reachable), importedFrom = ctx.fileFunctionNames.get(typeFile)?.has(name) ? typeFile : resolveReExport(name, typeFile, ctx.importSymbolMap, ctx.fileFunctionNames);
30425
- return named.find((c) => c.file === importedFrom) ?? (dot < 0 && named.length === 1 ? named[0] : void 0);
30688
+ let target = typeFile === filePath ? { file: typeFile, name } : ctx.resolveImported(typeFile, name), named = (ctx.classes.byName.get(target?.name ?? name) ?? []).filter(reachable);
30689
+ return named.find((c) => c.file === target?.file) ?? (dot < 0 && named.length === 1 ? named[0] : void 0);
30426
30690
  }
30427
30691
  function methodOrder(ctx, cls, fromTest) {
30428
30692
  let memo = fromTest ? ctx.methodOrders.test : ctx.methodOrders.production, reachable = (c) => fromTest || !c.test, ordering = /* @__PURE__ */ new Set(), external = (name) => {
@@ -30508,8 +30772,10 @@ function typedReceiverTargets(ctx, typeName, member, filePath, via = {}) {
30508
30772
  return targets.map((c) => ({ file: c.file, className: c.name }));
30509
30773
  }
30510
30774
  function returnedClass(ctx, fn, awaited, filePath) {
30511
- let name = ctx.aliasMap.get(filePath)?.get(fn) ?? fn, imported = ctx.importSymbolMap.get(filePath)?.get(fn), file = imported ? ctx.fileFunctionNames.get(imported)?.has(name) ? imported : resolveReExport(name, imported, ctx.importSymbolMap, ctx.fileFunctionNames) : filePath, declared = file ? ctx.returnTypes(file)?.get(name) : void 0;
30512
- if (!file || !declared || declared.promised && !awaited) return;
30775
+ let name = ctx.aliasMap.get(filePath)?.get(fn) ?? fn, imported = ctx.importSymbolMap.get(filePath)?.get(fn), target = imported ? ctx.resolveImported(imported, name) : { file: filePath, name };
30776
+ if (!target) return;
30777
+ let { file } = target, declared = ctx.returnTypes(file)?.get(target.name);
30778
+ if (!declared || declared.promised && !awaited) return;
30513
30779
  let fromTest = isTestFile(file);
30514
30780
  return declaredClass(ctx, declared.name, file, (c) => fromTest || !c.test) ? { name: declared.name, file } : void 0;
30515
30781
  }
@@ -30839,28 +31105,35 @@ function queryLocalBlastRadius(graph, request) {
30839
31105
 
30840
31106
  // src/analysis/local-analyzer.ts
30841
31107
  function analyzeSavedCallers(input2, request, parser3) {
30842
- let registry = new ExportRegistry(), files = [], dynamic = /* @__PURE__ */ new Map(), incomplete = input2.incomplete;
31108
+ let registry = new ExportRegistry(), files = [], dynamic = /* @__PURE__ */ new Map(), knownFiles = new Set(input2.sources.keys()), resolver = createCapturedTypeScriptResolver(knownFiles, input2.configFiles), incomplete = input2.incomplete;
30843
31109
  for (let [filePath, bytes] of input2.sources)
30844
31110
  try {
30845
- let python = filePath.endsWith(".py"), parse2 = python ? parser3.parsePythonSource : parser3.parseTypeScriptSource, callFacts, pythonClasses, dynamicImports, parsed = parse2(bytes, filePath, (tree, file) => {
30846
- tree.hasError && (incomplete = !0), callFacts = readRegistryCallFacts(tree, file, input2.repoName), python ? pythonClasses = readPythonClasses(tree) : dynamicImports = readDynamicImportCandidates(tree);
31111
+ let python = filePath.endsWith(".py"), parse2 = python ? parser3.parsePythonSource : parser3.parseTypeScriptSource, callFacts, pythonClasses, dynamicImports, namedReExports, parsed = parse2(bytes, filePath, (tree, file) => {
31112
+ tree.hasError && (incomplete = !0), callFacts = readRegistryCallFacts(tree, file, input2.repoName), python ? pythonClasses = readPythonClasses(tree) : (dynamicImports = bindDynamicImportCandidates(
31113
+ readDynamicImportCandidates(tree),
31114
+ filePath,
31115
+ resolver.resolveSpecifier
31116
+ ), namedReExports = readNamedReExports(
31117
+ tree,
31118
+ filePath,
31119
+ resolver.resolveSpecifier,
31120
+ dynamicImports,
31121
+ file.exports,
31122
+ knownFiles
31123
+ ));
30847
31124
  });
30848
31125
  if (files.push(parsed), registry.addFromParsed([parsed], input2.repoName), callFacts) {
30849
31126
  for (let [uid, sites] of callFacts.callSites)
30850
31127
  registry.addCallSites(uid, parsed.path, sites);
30851
31128
  registry.addReturnTypes(parsed.path, callFacts.returnTypes);
30852
31129
  }
30853
- pythonClasses && registry.addPythonClasses(parsed.path, pythonClasses), dynamicImports && dynamic.set(parsed.path, dynamicImports);
31130
+ pythonClasses && registry.addPythonClasses(parsed.path, pythonClasses), namedReExports && registry.addNamedReExports(parsed.path, namedReExports), dynamicImports && dynamic.set(parsed.path, dynamicImports);
30854
31131
  } catch (error2) {
30855
31132
  if (isWasmAbort(error2)) throw error2;
30856
31133
  incomplete = !0;
30857
31134
  }
30858
- let resolver = createCapturedTypeScriptResolver(input2.sources.keys(), input2.configFiles);
30859
- for (let [filePath, candidates] of dynamic) {
30860
- if (candidates.length === 0) continue;
30861
- let sites = bindDynamicImportCandidates(candidates, filePath, resolver.resolveSpecifier);
30862
- registry.addDynamicImports(filePath, resolveDynamicImportSites(sites, filePath, files));
30863
- }
31135
+ for (let [filePath, sites] of dynamic)
31136
+ sites.length !== 0 && registry.addDynamicImports(filePath, resolveDynamicImportSites(sites, filePath, files));
30864
31137
  let stats = {
30865
31138
  resolvedCount: 0,
30866
31139
  unresolvedCount: 0,
@@ -30895,7 +31168,7 @@ function analyzeSavedCallers(input2, request, parser3) {
30895
31168
  functions: file.functions
30896
31169
  })),
30897
31170
  trace,
30898
- incomplete: incomplete || unresolvedDynamic || stats.unresolvedCount > 0
31171
+ incomplete: incomplete || !!trace.untraced?.length || unresolvedDynamic || stats.unresolvedCount > 0
30899
31172
  },
30900
31173
  request
30901
31174
  );
Binary file
package/package.json CHANGED
@@ -1,8 +1,12 @@
1
1
  {
2
2
  "name": "@pharaoh-so/local-analyzer",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "type": "module",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/Pharaoh-so/pharaoh.git"
9
+ },
6
10
  "engines": {
7
11
  "node": ">=18"
8
12
  },