Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 9 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,16 @@

## 安装

### 从NuGet安装

```bash
dotnet add package TypeScriptParser
```

或通过包管理器控制台:

```powershell
Install-Package TypeScriptParser
```
## 文档

也可以访问 [NuGet包页面](https://www.nuget.org/packages/TypeScriptParser) 查看更多安装选项。
- [使用指南](docs/USAGE_GUIDE.md) - 快速开始和常用示例
- [API参考](docs/API_REFERENCE.md) - 完整的API文档

## 快速开始
## 构建项目

```bash
# 1. 构建native库
Expand All @@ -36,6 +31,10 @@ dotnet test --configuration Release

# 4. 打包NuGet包
dotnet pack -c Release -o ./artifacts

# 5. 测试打包
dotnet package add TypeScriptParser --project TypeScriptParser.TestPackage/ --version 0.0.1-dev
dotnet test TypeScriptParser.TestPackage
```

## 项目结构
Expand All @@ -44,15 +43,7 @@ dotnet pack -c Release -o ./artifacts
- [`TypeScriptParser.Native/`](TypeScriptParser.Native/) - 跨平台Native库包
- [`TypeScriptParser.Tests/`](TypeScriptParser.Tests/) - 单元测试

## 开发指南

### Debug模式构建
```bash
dotnet build -c Debug
dotnet test --configuration Debug
```

### 支持平台
## 支持平台
- Linux x64
- macOS ARM64
- Windows x64
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<!-- 测试项目不需要XML文档注释 -->
<NoWarn>$(NoWarn);CS1591</NoWarn>
</PropertyGroup>

<ItemGroup>
Expand Down
9 changes: 6 additions & 3 deletions TypeScriptParser.TestPackage/UnitTest1.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Xunit;
using TypeScriptParser;

namespace TypeScriptParser.TestPackage;

Expand All @@ -7,14 +8,16 @@ public class UnitTest1
[Fact]
public void Can_Create_Parser()
{
using var parser = new TreeSitter.TypeScript.TypeScriptParser();
Assert.True(parser.IsAvailable);
using var parser = new Parser();
// 通过能否成功解析来验证Parser可用性
var tree = parser.ParseString("const x = 1;");
Assert.NotNull(tree);
}

[Fact]
public void Can_Parse_Code()
{
using var parser = new TreeSitter.TypeScript.TypeScriptParser();
using var parser = new Parser();
var tree = parser.ParseString("const x = 1;");
Assert.Equal("program", tree.root_node().type());
}
Expand Down
11 changes: 6 additions & 5 deletions TypeScriptParser.Tests/TypeScriptAnalyzer.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
using System;
using System.Collections.Generic;
using GitHub.TreeSitter;
using TypeScriptParser.TreeSitter;
using System.Runtime.InteropServices;
using TypeScriptParser;

namespace TreeSitter.TypeScript
namespace TypeScriptParser.Tests
{
// 参数信息结构
public class Parameter
Expand All @@ -28,13 +29,13 @@ public class ExportedFunction
// TypeScript分析器模块
public class TypeScriptAnalyzer : IDisposable
{
private readonly TypeScriptParser parser;
private readonly Parser parser;
private readonly List<ExportedFunction> exportedFunctions = [];
private bool disposed = false;

public TypeScriptAnalyzer()
{
parser = new TypeScriptParser();
parser = new Parser();
}

public List<ExportedFunction> AnalyzeFile(string fileContent)
Expand All @@ -49,7 +50,7 @@ public List<ExportedFunction> AnalyzeFile(string fileContent)
return exportedFunctions;
}

using var cursor = parser.CreateCursor(tree);
using var cursor = new TSCursor(tree.root_node(), tree.language());
TraverseForExports(cursor, fileContent);

return [.. exportedFunctions];
Expand Down
2 changes: 2 additions & 0 deletions TypeScriptParser.Tests/TypeScriptParser.Tests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
<Nullable>disable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
<!-- 测试项目不需要XML文档注释 -->
<NoWarn>$(NoWarn);CS1591</NoWarn>
</PropertyGroup>

<ItemGroup>
Expand Down
197 changes: 197 additions & 0 deletions TypeScriptParser.Tests/tests/ExportExtractorTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Xunit;
using TypeScriptParser;
using TypeScriptParser.TreeSitter;

namespace TypeScriptParser.Tests
{
public class ExportExtractorTests
{
[Fact]
public void ExtractExportFunctions_SimpleExport_ShouldReturnFunctionNames()
{
// Arrange
string code = @"
export function add(a: number, b: number): number {
return a + b;
}

export function multiply(x: number, y: number): number {
return x * y;
}";

// Act
var exportedFunctions = ExtractExportFunctions(code);

// Assert
Assert.Equal(2, exportedFunctions.Count);
Assert.Contains("add", exportedFunctions);
Assert.Contains("multiply", exportedFunctions);
}

[Fact]
public void ExtractExportFunctions_MixedExports_ShouldOnlyReturnFunctions()
{
// Arrange
string code = @"
export function add(a: number, b: number): number {
return a + b;
}

function helper() {
return 'not exported';
}

export const PI = 3.14;

export function multiply(x: number, y: number): number {
return x * y;
}";

// Act
var exportedFunctions = ExtractExportFunctions(code);

// Assert
Assert.Equal(2, exportedFunctions.Count);
Assert.Contains("add", exportedFunctions);
Assert.Contains("multiply", exportedFunctions);
Assert.DoesNotContain("helper", exportedFunctions);
Assert.DoesNotContain("PI", exportedFunctions);
}

[Fact]
public void ExtractExportFunctions_NoExports_ShouldReturnEmpty()
{
// Arrange
string code = @"
function helper() {
return 'not exported';
}

const PI = 3.14;";

// Act
var exportedFunctions = ExtractExportFunctions(code);

// Assert
Assert.Empty(exportedFunctions);
}

[Fact]
public void ExtractExportFunctions_EmptyCode_ShouldReturnEmpty()
{
// Arrange
string code = "";

// Act
var exportedFunctions = ExtractExportFunctions(code);

// Assert
Assert.Empty(exportedFunctions);
}

[Fact]
public void ExtractExportFunctions_ComplexExports_ShouldExtractAllFunctions()
{
// Arrange
string code = @"
export function calculate(x: number): number {
return x * 2;
}

export function processData(data: any[]): any[] {
return data.filter(item => item != null);
}

export function validateInput(input: string): boolean {
return input && input.length > 0;
}

// 非函数导出
export const config = { api: 'https://api.example.com' };
export let counter = 0;

// 非导出函数
function internalHelper() {
return 'internal';
}";

// Act
var exportedFunctions = ExtractExportFunctions(code);

// Assert
Assert.Equal(3, exportedFunctions.Count);
Assert.Contains("calculate", exportedFunctions);
Assert.Contains("processData", exportedFunctions);
Assert.Contains("validateInput", exportedFunctions);
Assert.DoesNotContain("internalHelper", exportedFunctions);
}

[Fact]
public void ExtractExportFunctions_AsyncFunctions_ShouldExtractAsyncFunctions()
{
// Arrange
string code = @"
export async function fetchData(url: string): Promise<any> {
const response = await fetch(url);
return response.json();
}

export function syncFunction(): string {
return 'sync';
}";

// Act
var exportedFunctions = ExtractExportFunctions(code);

// Assert
Assert.Equal(2, exportedFunctions.Count);
Assert.Contains("fetchData", exportedFunctions);
Assert.Contains("syncFunction", exportedFunctions);
}

/// <summary>
/// 提取TypeScript代码中所有导出的函数名称
/// </summary>
/// <param name="code">TypeScript源代码</param>
/// <returns>导出函数名称列表</returns>
private List<string> ExtractExportFunctions(string code)
{
var exportedFunctions = new List<string>();

using var parser = new Parser();
using var tree = parser.ParseString(code);

// 创建查询匹配 export 函数
var query = tree.language().query_new(@"
(export_statement
declaration: (function_declaration
name: (identifier) @func_name))
", out var offset, out var error);

if (query != null && error == TSQueryError.TSQueryErrorNone)
{
using var cursor = new TSQueryCursor();
cursor.exec(query, tree.root_node());

while (cursor.next_match(out var match, out var captures))
{
foreach (var capture in captures)
{
var funcName = capture.node.text(code);
if (!string.IsNullOrWhiteSpace(funcName))
{
exportedFunctions.Add(funcName);
}
}
}

query.Dispose();
}

return exportedFunctions;
}
}
}
2 changes: 1 addition & 1 deletion TypeScriptParser.Tests/tests/TypeScriptAnalyzerTests.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
using System;
using System.IO;
using Xunit;
using TreeSitter.TypeScript;
using TypeScriptParser.Tests;

namespace TypeScriptParser.Tests
{
Expand Down
Loading
Loading