elastic / elastic/semantic-code-search-indexer
feat: Add Export Alias Tracking for TypeScript/JavaScript
- Dominant language
- TypeScript
- Stars
- 19
- Forks
- 10
- PR merge metrics
- No merged PRs in 30d
Description
# Enhancement: Add Export Alias Tracking for TypeScript/JavaScript
## Overview
Enhance the export detection to track both the original name and alias name for re-exported symbols. Currently, when code uses `export { originalName as aliasName }`, we only capture the alias. Tracking both enables better dependency analysis and code navigation.
## Current Behavior
For re-exports with aliasing:
```typescript
export { MyClass as MyClassAlias } from './module';
export { foo as bar };
```
The current implementation only captures the **alias name** (`MyClassAlias`, `bar`), but not the original name (`MyClass`, `foo`).
## Desired Behavior
Capture both the original name and the alias to enable full tracking:
```typescript
{
"exports": [
{
"name": "MyClassAlias", // What's exported
"type": "named",
"original": "MyClass", // Where it comes from (NEW)
"target": "src/module" // Module path (for re-exports)
}
]
}
```
## Implementation Plan
### 1. Update Type Definition ✅
**File**: `src/utils/elasticsearch.ts`
Add `original` field to export structure:
```typescript
export interface ExportInfo {
name: string; // Exported symbol name (alias if aliased)
type: 'named' | 'default' | 'namespace'; // Export type
target?: string; // For re-exports: source module path
original?: string; // For aliased exports: original symbol name
}
export interface CodeChunk {
// ... existing fields ...
exports?: ExportInfo[];
}
```
### 2. Update Elasticsearch Mapping ✅
**File**: `src/utils/elasticsearch.ts` (in `createIndex` function)
Add `original` field to the nested exports mapping:
```typescript
exports: {
type: 'nested',
properties: {
name: { type: 'keyword' },
type: { type: 'keyword' },
target: { type: 'keyword' },
original: { type: 'keyword' }, // NEW
},
}
```
### 3. Update TypeScript Export Queries ✅
**File**: `src/languages/typescript.ts`
Update the export specifier queries to capture both names:
```typescript
// Current query only captures alias:
'(export_statement (export_clause (export_specifier name: (identifier) alias: (identifier) @export.name)))'
// Update to capture both:
'(export_statement (export_clause (export_specifier name: (identifier) @export.original alias: (identifier) @export.name)))'
// For non-aliased exports, keep existing:
'(export_statement (export_clause (export_specifier name: (identifier) @export.name)))'
```
### 4. Update JavaScript Export Queries ✅
**File**: `src/languages/javascript.ts`
Apply the same updates as TypeScript since JavaScript uses identical export syntax.
### 5. Update Parser Logic ✅
**File**: `src/utils/parser.ts` (in `parseWithTreeSitter` method)
Update the export processing to capture and store the original name:
```typescript
for (const capture of match.captures) {
if (capture.name === 'export.name') {
exportName = capture.node.text;
} else if (capture.name === 'export.original') {
exportOriginal = capture.node.text; // NEW
}
// ... existing logic
}
// When adding to exportsByLine:
exportsByLine[line].push({
name: exportName,
type: exportType,
...(exportTarget && { target: exportTarget }),
...(exportOriginal && { original: exportOriginal }), // NEW
});
```
### 6. Add Tests ✅
**File**: `tests/parser.test.ts`
Add test cases for aliased exports:
```typescript
it('should extract export aliases correctly', () => {
// Test file with:
// export { MyClass as MyClassAlias } from './module';
// export { foo as bar };
const allExports = chunks.flatMap(chunk => chunk.exports || []);
expect(allExports).toEqual(
expect.arrayContaining([
expect.objectContaining({
name: 'MyClassAlias',
original: 'MyClass',
type: 'named',
target: 'tests/fixtures/module'
}),
expect.objectContaining({
name: 'bar',
original: 'foo',
type: 'named'
}),
])
);
});
```
**Update test fixtures**:
- `tests/fixtures/typescript.ts` - Add aliased export examples
- `tests/fixtures/javascript.js` - Add aliased export examples
### 7. Update Documentation ✅
**File**: `docs/EXPORTS_IMPLEMENTATION.md`
Add section on export aliasing:
```markdown
### Export Aliasing
For aliased exports, both the alias (exported name) and original (source name) are captured:
**Example**:
```typescript
export { MyClass as MyClassAlias } from './module';
```
**Output**:
```json
{
"exports": [
{
"name": "MyClassAlias",
"original": "MyClass",
"type": "named",
"target": "src/module"
}
]
}
```
```
## Use Cases Enabled
1. **Dependency Tracking**: Understand the complete export chain even when symbols are renamed
2. **Refactoring Support**: Find all places where a symbol is re-exported under different names
3. **Code Navigation**: Navigate from an aliased export back to its original definition
4. **API Documentation**: Generate complete API docs showing both public names and their sources
## Breaking Changes
None. The `original` field is optional and backward compatible with existing export data.
## Related
- Builds on PR #68 (Add exports field to CodeChunk type)
- Complements existing `target` field for re-export source tracking
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.