Skip to content

Commit b0e1eb8

Browse files
committed
add document generate
1 parent a04749f commit b0e1eb8

File tree

18 files changed

+323
-12
lines changed

18 files changed

+323
-12
lines changed
Lines changed: 94 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,100 @@
1-
namespace EmmyLua.Cli.DocGenerator;
1+
using Docfx;
2+
using EmmyLua.Cli.DocGenerator.Markdown;
3+
using EmmyLua.Cli.DocGenerator.Proto;
4+
using EmmyLua.CodeAnalysis.Workspace;
5+
using EmmyLua.Configuration;
6+
using YamlDotNet.Serialization;
7+
8+
namespace EmmyLua.Cli.DocGenerator;
29

310
public class DocGenerator(DocOptions options)
411
{
5-
public void Generate()
12+
private string ApisPath { get; } = Path.Combine(options.Output, "apis");
13+
14+
public async Task<int> Run()
15+
{
16+
if (!Directory.Exists(options.Output))
17+
{
18+
Directory.CreateDirectory(options.Output);
19+
}
20+
21+
try
22+
{
23+
if (Directory.Exists(ApisPath))
24+
{
25+
Directory.Delete(ApisPath, true);
26+
}
27+
}
28+
catch (IOException ex)
29+
{
30+
Console.WriteLine($"can not delete directory {ApisPath}: {ex.Message}");
31+
}
32+
catch (UnauthorizedAccessException ex)
33+
{
34+
Console.WriteLine($"not enough permission {ApisPath}: {ex.Message}");
35+
}
36+
37+
Directory.CreateDirectory(ApisPath);
38+
39+
DocfxInit();
40+
var luaWorkspace = LoadLuaWorkspace();
41+
GenerateApis(luaWorkspace);
42+
await Docfx.Docset.Build(Path.Combine(options.Output, "docfx.json"));
43+
44+
return 0;
45+
}
46+
47+
private void DocfxInit()
48+
{
49+
var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Template", "docfx.json");
50+
var docfxTemplate = File.ReadAllText(path);
51+
var docfxJson = docfxTemplate.Replace("{projectName}", options.ProjectName);
52+
File.WriteAllText(Path.Combine(options.Output, "docfx.json"), docfxJson);
53+
File.WriteAllText(Path.Combine(options.Output, "index.md"), $"# {options.ProjectName}\n");
54+
GenerateToc(options.Output, new List<TocItem>()
55+
{
56+
new TocItem()
57+
{
58+
Name = "Apis",
59+
Href = "apis/"
60+
}
61+
});
62+
}
63+
64+
private LuaWorkspace LoadLuaWorkspace()
65+
{
66+
var workspacePath = options.Workspace;
67+
var settingManager = new SettingManager();
68+
settingManager.LoadSetting(workspacePath);
69+
return LuaWorkspace.Create(workspacePath, settingManager.GetLuaFeatures());
70+
}
71+
72+
private void GenerateApis(LuaWorkspace luaWorkspace)
73+
{
74+
var tocItems = new List<TocItem>();
75+
foreach (var module in luaWorkspace.ModuleGraph.GetAllModules())
76+
{
77+
if (module.Workspace == luaWorkspace.MainWorkspace)
78+
{
79+
var renderer = new ModuleDoc(luaWorkspace.Compilation, module);
80+
var text = renderer.Build();
81+
var fileName = $"{module.ModulePath}.md";
82+
tocItems.Add(new TocItem()
83+
{
84+
Name = module.ModulePath,
85+
Href = fileName
86+
});
87+
File.WriteAllText(Path.Combine(ApisPath, fileName), text);
88+
}
89+
}
90+
91+
GenerateToc(ApisPath, tocItems);
92+
}
93+
94+
private void GenerateToc(string path, List<TocItem> tocItems)
695
{
7-
// var docfx = Docfx.Docset.Build("")
96+
var serializer = new SerializerBuilder().Build();
97+
var yaml = serializer.Serialize(tocItems);
98+
File.WriteAllText(Path.Combine(path, "toc.yml"), yaml);
899
}
9100
}

EmmyLua.Cli/DocGenerator/DocOptions.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ public class DocOptions
77
[Option('w', "workspace", Required = true, HelpText = "Workspace directory")]
88
public string Workspace { get; set; } = string.Empty;
99

10+
[Option('p', "project", Required = true, HelpText = "Project name")]
11+
public string ProjectName { get; set; } = string.Empty;
12+
1013
[Option('o', "output", Required = true, HelpText = "Output directory")]
1114
public string Output { get; set; } = string.Empty;
1215
}
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
using EmmyLua.CodeAnalysis.Compilation;
2+
using EmmyLua.CodeAnalysis.Compilation.Declaration;
3+
using EmmyLua.CodeAnalysis.Compilation.Infer;
4+
using EmmyLua.CodeAnalysis.Compilation.Semantic.Render;
5+
using EmmyLua.CodeAnalysis.Compilation.Semantic.Render.Renderer;
6+
using EmmyLua.CodeAnalysis.Document;
7+
using EmmyLua.CodeAnalysis.Syntax.Node.SyntaxNodes;
8+
using EmmyLua.CodeAnalysis.Workspace.Module;
9+
10+
namespace EmmyLua.Cli.DocGenerator.Markdown;
11+
12+
public class ModuleDoc
13+
{
14+
private SearchContext SearchContext { get; }
15+
16+
private LuaRenderContext RenderContext { get; }
17+
18+
private LuaRenderBuilder RenderBuilder { get; }
19+
20+
private ModuleIndex ModuleIndex { get; }
21+
22+
private LuaRenderFeature Feature { get; } = new LuaRenderFeature()
23+
{
24+
ShowTypeLink = false,
25+
ExpandAlias = false,
26+
};
27+
28+
public ModuleDoc(LuaCompilation compilation, ModuleIndex moduleIndex)
29+
{
30+
SearchContext = new SearchContext(compilation, new SearchContextFeatures());
31+
RenderBuilder = new LuaRenderBuilder(SearchContext);
32+
ModuleIndex = moduleIndex;
33+
RenderContext = new LuaRenderContext(SearchContext, Feature);
34+
}
35+
36+
public string Build()
37+
{
38+
RenderContext.AddH1Title(ModuleIndex.ModulePath);
39+
var document = SearchContext.Compilation.Workspace.GetDocument(ModuleIndex.DocumentId);
40+
if (document is null)
41+
{
42+
return RenderContext.GetText();
43+
}
44+
45+
RenderModuleDescription(document);
46+
RenderContext.AppendLine();
47+
48+
RenderContext.AddH2Title("Public members:");
49+
RenderContext.AddSeparator();
50+
RenderModuleMembers(document);
51+
52+
return RenderContext.GetText();
53+
}
54+
55+
private void RenderModuleDescription(LuaDocument document)
56+
{
57+
RenderContext.Append(RenderBuilder.RenderModule(document, Feature));
58+
}
59+
60+
private IEnumerable<LuaFuncStatSyntax> GetModuleStats(LuaDocument document)
61+
{
62+
if (document.SyntaxTree.SyntaxRoot?.Block is { StatList: { } statList })
63+
{
64+
foreach (var funcStat in statList.OfType<LuaFuncStatSyntax>())
65+
{
66+
yield return funcStat;
67+
}
68+
}
69+
}
70+
71+
private void RenderModuleMembers(LuaDocument document)
72+
{
73+
foreach (var funcStat in GetModuleStats(document))
74+
{
75+
if (funcStat is { NameElement.Parent: { } node })
76+
{
77+
var declaration = SearchContext.FindDeclaration(node);
78+
if (declaration is not null)
79+
{
80+
RenderFuncDeclaration(declaration, funcStat);
81+
RenderContext.AddSeparator();
82+
}
83+
}
84+
}
85+
}
86+
87+
private void RenderFuncDeclaration(LuaDeclaration declaration, LuaFuncStatSyntax funcStat)
88+
{
89+
if (declaration.IsLocal || declaration.IsPrivate)
90+
{
91+
return;
92+
}
93+
94+
var asyncText = declaration.IsAsync ? "async " : string.Empty;
95+
96+
if (declaration.Info is MethodInfo methodInfo)
97+
{
98+
if (methodInfo.IndexPtr.ToNode(SearchContext) is { } indexExpr)
99+
{
100+
RenderContext.WrapperLua(() =>
101+
{
102+
RenderContext.Append($"{asyncText}function {indexExpr.Text}");
103+
LuaTypeRenderer.RenderFunc(methodInfo.Method, RenderContext);
104+
});
105+
}
106+
else if (methodInfo.NamePtr.ToNode(SearchContext) is { } nameExpr)
107+
{
108+
RenderContext.WrapperLua(() =>
109+
{
110+
RenderContext.Append($"{asyncText}function {nameExpr.Text}");
111+
LuaTypeRenderer.RenderFunc(methodInfo.Method, RenderContext);
112+
});
113+
}
114+
115+
var comments = funcStat.Comments;
116+
foreach (var comment in comments)
117+
{
118+
if (comment.CommentText is { Length: > 0 } commentText)
119+
{
120+
// RenderContext.Append(" ");
121+
RenderContext.Append(commentText); //.Replace("\n", "\n "));
122+
}
123+
124+
RenderContext.AppendLine();
125+
}
126+
}
127+
}
128+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using YamlDotNet.Serialization;
2+
3+
namespace EmmyLua.Cli.DocGenerator.Proto;
4+
5+
public class TocItem
6+
{
7+
[YamlMember(Alias = "name")]
8+
public string Name { get; set; } = string.Empty;
9+
10+
[YamlMember(Alias = "href")]
11+
public string Href { get; set; } = string.Empty;
12+
}

EmmyLua.Cli/EmmyLua.Cli.csproj

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,7 @@
1616
<PackageReference Include="Docfx.App" Version="2.76.0" />
1717
</ItemGroup>
1818

19+
<ItemGroup>
20+
<Content Include="Template\**" CopyToOutputDirectory="PreserveNewest" />
21+
</ItemGroup>
1922
</Project>

EmmyLua.Cli/Program.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
.WithParsed<DocOptions>(o =>
1717
{
1818
var docGenerator = new DocGenerator(o);
19-
docGenerator.Generate();
19+
var exitCode = docGenerator.Run();
20+
Environment.Exit(exitCode.GetAwaiter().GetResult());
2021
});
2122
break;
2223
}

EmmyLua.Cli/Template/docfx.json

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"build": {
3+
"content": [
4+
{
5+
"files": [
6+
"**/*.{yml,md}"
7+
],
8+
"exclude": [
9+
"_site/**"
10+
]
11+
}
12+
],
13+
"resource": [
14+
{
15+
"files": [
16+
"images/**"
17+
]
18+
}
19+
],
20+
"output": "_site",
21+
"template": [
22+
"statictoc"
23+
],
24+
"globalMetadata": {
25+
"_appName": "{projectName}",
26+
"_appTitle": "{projectName}",
27+
"_enableSearch": true,
28+
"pdf": true
29+
}
30+
}
31+
}

EmmyLua/CodeAnalysis/Compilation/Infer/SearchContext.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ private LuaType InferCore(LuaSyntaxElement element)
9696
}
9797
}
9898

99-
private IEnumerable<LuaDeclaration> GetRawMembers(string name)
99+
public IEnumerable<LuaDeclaration> GetRawMembers(string name)
100100
{
101101
if (name is "_G" or "_ENV" or "global")
102102
{

EmmyLua/CodeAnalysis/Compilation/Semantic/Render/LuaRenderBuilder.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Globalization;
2+
using EmmyLua.CodeAnalysis.Compilation.Declaration;
23
using EmmyLua.CodeAnalysis.Compilation.Infer;
34
using EmmyLua.CodeAnalysis.Compilation.Semantic.Render.Renderer;
45
using EmmyLua.CodeAnalysis.Compilation.Type;
@@ -53,6 +54,13 @@ public string RenderModule(LuaDocument document, LuaRenderFeature feature)
5354
return renderContext.GetText();
5455
}
5556

57+
public string RenderDeclaration(LuaDeclaration declaration, LuaRenderFeature feature)
58+
{
59+
var renderContext = new LuaRenderContext(context, feature);
60+
LuaDeclarationRenderer.RenderDeclaration(declaration, renderContext);
61+
return renderContext.GetText();
62+
}
63+
5664
private void RenderElement(LuaSyntaxElement element, LuaRenderContext renderContext)
5765
{
5866
var declaration = renderContext.SearchContext.FindDeclaration(element);

EmmyLua/CodeAnalysis/Compilation/Semantic/Render/LuaRenderContext.cs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,10 +79,32 @@ public string GetText()
7979
RenderAliasExpand();
8080
}
8181

82-
RenderLink();
82+
if (Feature.ShowTypeLink)
83+
{
84+
RenderLink();
85+
}
86+
8387
return _sb.ToString();
8488
}
8589

90+
public void AddH1Title(string title)
91+
{
92+
_sb.Append("# ");
93+
_sb.Append(title);
94+
}
95+
96+
public void AddH2Title(string title)
97+
{
98+
_sb.Append("## ");
99+
_sb.Append(title);
100+
}
101+
102+
public void AddH3Title(string title)
103+
{
104+
_sb.Append("### ");
105+
_sb.Append(title);
106+
}
107+
86108
private void RenderLink()
87109
{
88110
if (Feature.ShowTypeLink && _typeLinks.Count != 0)

0 commit comments

Comments
 (0)