ucn 3.1.0 → 3.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.

Potentially problematic release.


This version of ucn might be problematic. Click here for more details.

package/core/imports.js CHANGED
@@ -431,6 +431,12 @@ function resolveImport(importPath, fromFile, config = {}) {
431
431
  }
432
432
  }
433
433
 
434
+ // Check Go module imports
435
+ if (config.language === 'go') {
436
+ const resolved = resolveGoImport(importPath, fromFile, config.root);
437
+ if (resolved) return resolved;
438
+ }
439
+
434
440
  return null; // External package
435
441
  }
436
442
 
@@ -439,6 +445,83 @@ function resolveImport(importPath, fromFile, config = {}) {
439
445
  return resolveFilePath(resolved, config.extensions || getExtensions(config.language));
440
446
  }
441
447
 
448
+ // Cache for Go module paths
449
+ const goModuleCache = new Map();
450
+
451
+ /**
452
+ * Find and parse go.mod to get the module path
453
+ * @param {string} startDir - Directory to start searching from
454
+ * @returns {{modulePath: string, root: string}|null}
455
+ */
456
+ function findGoModule(startDir) {
457
+ // Check cache first
458
+ if (goModuleCache.has(startDir)) {
459
+ return goModuleCache.get(startDir);
460
+ }
461
+
462
+ let dir = startDir;
463
+ while (dir !== path.dirname(dir)) {
464
+ const goModPath = path.join(dir, 'go.mod');
465
+ if (fs.existsSync(goModPath)) {
466
+ try {
467
+ const content = fs.readFileSync(goModPath, 'utf-8');
468
+ // Parse module line: module github.com/user/project
469
+ const match = content.match(/^module\s+(\S+)/m);
470
+ if (match) {
471
+ const result = { modulePath: match[1], root: dir };
472
+ goModuleCache.set(startDir, result);
473
+ return result;
474
+ }
475
+ } catch (e) {
476
+ // Ignore read errors
477
+ }
478
+ }
479
+ dir = path.dirname(dir);
480
+ }
481
+
482
+ goModuleCache.set(startDir, null);
483
+ return null;
484
+ }
485
+
486
+ /**
487
+ * Resolve Go package import to local files
488
+ * @param {string} importPath - Go import path (e.g., "github.com/user/proj/pkg/util")
489
+ * @param {string} fromFile - File containing the import
490
+ * @param {string} projectRoot - Project root directory
491
+ * @returns {string|null} - Directory path containing the package, or null if external
492
+ */
493
+ function resolveGoImport(importPath, fromFile, projectRoot) {
494
+ const goMod = findGoModule(path.dirname(fromFile));
495
+ if (!goMod) return null;
496
+
497
+ const { modulePath, root } = goMod;
498
+
499
+ // Check if the import is within this module
500
+ if (importPath.startsWith(modulePath)) {
501
+ // Convert module path to relative path
502
+ // e.g., "github.com/user/proj/pkg/util" -> "pkg/util"
503
+ const relativePath = importPath.slice(modulePath.length).replace(/^\//, '');
504
+ const pkgDir = path.join(root, relativePath);
505
+
506
+ // Go imports are directories, find a .go file in the directory
507
+ if (fs.existsSync(pkgDir) && fs.statSync(pkgDir).isDirectory()) {
508
+ // Return the first .go file in the directory (not _test.go)
509
+ try {
510
+ const files = fs.readdirSync(pkgDir);
511
+ for (const file of files) {
512
+ if (file.endsWith('.go') && !file.endsWith('_test.go')) {
513
+ return path.join(pkgDir, file);
514
+ }
515
+ }
516
+ } catch (e) {
517
+ // Ignore read errors
518
+ }
519
+ }
520
+ }
521
+
522
+ return null;
523
+ }
524
+
442
525
  /**
443
526
  * Try to resolve a path with various extensions
444
527
  */
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ucn",
3
- "version": "3.1.0",
4
- "description": "Code navigation built by AI, for AI. Reduces context usage by 90%+ when working with large codebases.",
3
+ "version": "3.1.1",
4
+ "description": "Code navigation built by AI, for AI. Reduces context usage when working with large codebases.",
5
5
  "main": "index.js",
6
6
  "bin": {
7
7
  "ucn": "./cli/index.js"
@@ -4297,6 +4297,53 @@ class Product {
4297
4297
  fs.rmSync(tmpDir, { recursive: true, force: true });
4298
4298
  }
4299
4299
  });
4300
+
4301
+ it('should resolve Go module imports for exporters', () => {
4302
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ucn-go-import-'));
4303
+ try {
4304
+ // Create go.mod file
4305
+ fs.writeFileSync(path.join(tmpDir, 'go.mod'), `module example.com/myproject
4306
+
4307
+ go 1.21
4308
+ `);
4309
+
4310
+ // Create package structure
4311
+ fs.mkdirSync(path.join(tmpDir, 'pkg', 'config'), { recursive: true });
4312
+ fs.writeFileSync(path.join(tmpDir, 'pkg', 'config', 'config.go'), `package config
4313
+
4314
+ type Config struct {
4315
+ Name string
4316
+ }
4317
+
4318
+ func NewConfig() *Config {
4319
+ return &Config{}
4320
+ }
4321
+ `);
4322
+
4323
+ fs.writeFileSync(path.join(tmpDir, 'main.go'), `package main
4324
+
4325
+ import "example.com/myproject/pkg/config"
4326
+
4327
+ func main() {
4328
+ cfg := config.NewConfig()
4329
+ _ = cfg
4330
+ }
4331
+ `);
4332
+
4333
+ const index = new ProjectIndex(tmpDir);
4334
+ index.build('**/*.go', { quiet: true });
4335
+
4336
+ // Get exporters for the config package
4337
+ const exportersResult = index.exporters(path.join(tmpDir, 'pkg', 'config', 'config.go'));
4338
+ assert.ok(exportersResult.length > 0, 'Should find files that import the config package');
4339
+
4340
+ // main.go should be in the list
4341
+ const mainFile = exportersResult.find(e => e.file.includes('main.go'));
4342
+ assert.ok(mainFile, 'main.go should import the config package');
4343
+ } finally {
4344
+ fs.rmSync(tmpDir, { recursive: true, force: true });
4345
+ }
4346
+ });
4300
4347
  });
4301
4348
 
4302
4349
  console.log('UCN v3 Test Suite');