regen.mde 0.2.2
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/LICENSE +16 -0
- package/README.md +295 -0
- package/bin/build-corpus-editor.js +81 -0
- package/bin/build-corpus.js +41 -0
- package/bin/postinstall.js +187 -0
- package/bin/regen-mdeditor-install.js +27 -0
- package/bin/regen-mdeditor-uninstall.js +19 -0
- package/bin/validate-katex.js +93 -0
- package/desktop/BuildCorpusEditor/BuildCorpusBridge.cs +270 -0
- package/desktop/BuildCorpusEditor/BuildCorpusEditor.csproj +22 -0
- package/desktop/BuildCorpusEditor/EditorForm.cs +540 -0
- package/desktop/BuildCorpusEditor/Program.cs +81 -0
- package/desktop/BuildCorpusEditor/app.manifest +16 -0
- package/dist/release/regen.mde-0.2.2-win-x64-setup.exe +0 -0
- package/dist/release/regen.mde-0.2.2-win-x64.zip +0 -0
- package/dist/windows-editor/BuildCorpusEditor.deps.json +83 -0
- package/dist/windows-editor/BuildCorpusEditor.dll +0 -0
- package/dist/windows-editor/BuildCorpusEditor.exe +0 -0
- package/dist/windows-editor/BuildCorpusEditor.pdb +0 -0
- package/dist/windows-editor/BuildCorpusEditor.runtimeconfig.json +19 -0
- package/dist/windows-editor/Microsoft.Web.WebView2.Core.dll +0 -0
- package/dist/windows-editor/Microsoft.Web.WebView2.Core.xml +6817 -0
- package/dist/windows-editor/Microsoft.Web.WebView2.WinForms.dll +0 -0
- package/dist/windows-editor/Microsoft.Web.WebView2.WinForms.xml +510 -0
- package/dist/windows-editor/Microsoft.Web.WebView2.Wpf.dll +0 -0
- package/dist/windows-editor/Microsoft.Web.WebView2.Wpf.xml +1902 -0
- package/dist/windows-editor/WebView2Loader.dll +0 -0
- package/dist/windows-editor/runtimes/win-x64/native/WebView2Loader.dll +0 -0
- package/dist/windows-editor/wwwroot/assets/index-DjJ6xmhy.js +326 -0
- package/dist/windows-editor/wwwroot/assets/index-_dwMNNsm.css +1 -0
- package/dist/windows-editor/wwwroot/index.html +22 -0
- package/editor-web/index.html +21 -0
- package/editor-web/src/main.jsx +399 -0
- package/editor-web/src/styles.css +602 -0
- package/editor-web/vite.config.js +13 -0
- package/examples/build-corpus.config.example.json +21 -0
- package/installer/install-regen-mde.ps1 +175 -0
- package/installer/regen-mde.nsi +81 -0
- package/package.json +86 -0
- package/pyproject.toml +33 -0
- package/requirements.txt +4 -0
- package/scripts/build-windows-editor.ps1 +47 -0
- package/scripts/package-windows-editor.ps1 +90 -0
- package/scripts/run-corpus.ps1 +28 -0
- package/scripts/run-editor-implementation-plane.ps1 +203 -0
- package/scripts/run-required-tests.ps1 +98 -0
- package/scripts/run-smoke.ps1 +28 -0
- package/src/build_corpus/__init__.py +3 -0
- package/src/build_corpus/docx_exporter.py +798 -0
- package/src/build_corpus/exporter.py +1195 -0
- package/src/build_corpus/ppt_exporter.py +532 -0
- package/src/build_corpus/templates/__init__.py +1 -0
- package/src/build_corpus/templates/md-to-word-template.dotx +0 -0
- package/src/build_corpus/validate_assets.py +46 -0
- package/tools/audit_corpus.py +203 -0
- package/tools/collect_microsoft_word_templates.py +228 -0
- package/tools/collect_online_docx_corpus.py +272 -0
- package/tools/collect_online_pptx_corpus.py +252 -0
- package/tools/compare_pptx_inputs_outputs.py +87 -0
- package/tools/roundtrip_docx_corpus.py +171 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const katex = require("katex");
|
|
4
|
+
|
|
5
|
+
function extractMath(markdown) {
|
|
6
|
+
const spans = [];
|
|
7
|
+
const blockRe = /\$\$([\s\S]*?)\$\$/g;
|
|
8
|
+
let masked = markdown;
|
|
9
|
+
let match;
|
|
10
|
+
while ((match = blockRe.exec(markdown)) !== null) {
|
|
11
|
+
spans.push({ displayMode: true, tex: match[1].trim(), index: match.index });
|
|
12
|
+
}
|
|
13
|
+
masked = masked.replace(blockRe, "");
|
|
14
|
+
|
|
15
|
+
for (let i = 0; i < masked.length; i++) {
|
|
16
|
+
if (masked[i] !== "$" || isEscaped(masked, i)) continue;
|
|
17
|
+
let end = -1;
|
|
18
|
+
for (let j = i + 1; j < masked.length; j++) {
|
|
19
|
+
if (masked[j] === "\n") break;
|
|
20
|
+
if (masked[j] === "$" && !isEscaped(masked, j)) {
|
|
21
|
+
end = j;
|
|
22
|
+
break;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (end > i + 1) {
|
|
26
|
+
spans.push({ displayMode: false, tex: masked.slice(i + 1, end).trim(), index: i });
|
|
27
|
+
i = end;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return spans;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function isEscaped(text, index) {
|
|
34
|
+
let slashCount = 0;
|
|
35
|
+
for (let i = index - 1; i >= 0 && text[i] === "\\"; i--) {
|
|
36
|
+
slashCount++;
|
|
37
|
+
}
|
|
38
|
+
return slashCount % 2 === 1;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function validateFile(filePath) {
|
|
42
|
+
const markdown = fs.readFileSync(filePath, "utf8");
|
|
43
|
+
const spans = extractMath(markdown);
|
|
44
|
+
const failures = [];
|
|
45
|
+
for (const span of spans) {
|
|
46
|
+
try {
|
|
47
|
+
katex.renderToString(span.tex, {
|
|
48
|
+
displayMode: span.displayMode,
|
|
49
|
+
throwOnError: true,
|
|
50
|
+
strict: "ignore",
|
|
51
|
+
trust: false,
|
|
52
|
+
});
|
|
53
|
+
} catch (error) {
|
|
54
|
+
failures.push({
|
|
55
|
+
index: span.index,
|
|
56
|
+
displayMode: span.displayMode,
|
|
57
|
+
tex: span.tex.slice(0, 500),
|
|
58
|
+
error: error.message,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return {
|
|
63
|
+
file: filePath,
|
|
64
|
+
math_spans: spans.length,
|
|
65
|
+
failures: failures.length,
|
|
66
|
+
failure_samples: failures.slice(0, 50),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function main() {
|
|
71
|
+
const target = process.argv[2];
|
|
72
|
+
if (!target) {
|
|
73
|
+
console.error("Usage: node validate_katex.js <markdown-file-or-directory>");
|
|
74
|
+
process.exit(2);
|
|
75
|
+
}
|
|
76
|
+
const stat = fs.statSync(target);
|
|
77
|
+
const files = [];
|
|
78
|
+
if (stat.isDirectory()) {
|
|
79
|
+
for (const entry of fs.readdirSync(target, { recursive: true })) {
|
|
80
|
+
const full = path.join(target, entry);
|
|
81
|
+
if (fs.existsSync(full) && fs.statSync(full).isFile() && full.endsWith(".md")) {
|
|
82
|
+
files.push(full);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
} else {
|
|
86
|
+
files.push(target);
|
|
87
|
+
}
|
|
88
|
+
const results = files.map(validateFile);
|
|
89
|
+
console.log(JSON.stringify({ files: results.length, results }, null, 2));
|
|
90
|
+
process.exit(results.some((result) => result.failures > 0) ? 1 : 0);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
main();
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
using System.Diagnostics;
|
|
2
|
+
using System.Text.Json;
|
|
3
|
+
|
|
4
|
+
namespace BuildCorpusEditor;
|
|
5
|
+
|
|
6
|
+
internal sealed class BuildCorpusBridge
|
|
7
|
+
{
|
|
8
|
+
private readonly string? initialPath;
|
|
9
|
+
private readonly string root;
|
|
10
|
+
private readonly string sessionRoot;
|
|
11
|
+
|
|
12
|
+
public BuildCorpusBridge(string? initialPath)
|
|
13
|
+
{
|
|
14
|
+
this.initialPath = string.IsNullOrWhiteSpace(initialPath) ? null : Path.GetFullPath(initialPath);
|
|
15
|
+
root = LocateRoot();
|
|
16
|
+
sessionRoot = Path.Combine(Path.GetTempPath(), "build-corpus-editor");
|
|
17
|
+
Directory.CreateDirectory(sessionRoot);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
public StartupResult Startup() => new(initialPath);
|
|
21
|
+
|
|
22
|
+
public object? ChooseOpen()
|
|
23
|
+
{
|
|
24
|
+
using var dialog = new OpenFileDialog
|
|
25
|
+
{
|
|
26
|
+
Title = "Open Markdown, Word, or PowerPoint",
|
|
27
|
+
Filter = "Supported documents|*.md;*.markdown;*.docx;*.pptx;*.ppt|Markdown|*.md;*.markdown|Word|*.docx|PowerPoint|*.pptx;*.ppt|All files|*.*",
|
|
28
|
+
CheckFileExists = true,
|
|
29
|
+
};
|
|
30
|
+
return dialog.ShowDialog() == DialogResult.OK ? new { path = dialog.FileName } : new { path = "" };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
public async Task<object?> ChooseImageAsync()
|
|
34
|
+
{
|
|
35
|
+
using var dialog = new OpenFileDialog
|
|
36
|
+
{
|
|
37
|
+
Title = "Insert Image",
|
|
38
|
+
Filter = "Images|*.png;*.jpg;*.jpeg;*.gif;*.webp;*.bmp|All files|*.*",
|
|
39
|
+
CheckFileExists = true,
|
|
40
|
+
};
|
|
41
|
+
if (dialog.ShowDialog() != DialogResult.OK) return new { src = "", alt = "" };
|
|
42
|
+
|
|
43
|
+
var bytes = await File.ReadAllBytesAsync(dialog.FileName);
|
|
44
|
+
var extension = Path.GetExtension(dialog.FileName).ToLowerInvariant();
|
|
45
|
+
var mime = extension switch
|
|
46
|
+
{
|
|
47
|
+
".jpg" or ".jpeg" => "image/jpeg",
|
|
48
|
+
".gif" => "image/gif",
|
|
49
|
+
".webp" => "image/webp",
|
|
50
|
+
".bmp" => "image/bmp",
|
|
51
|
+
_ => "image/png",
|
|
52
|
+
};
|
|
53
|
+
return new
|
|
54
|
+
{
|
|
55
|
+
src = $"data:{mime};base64,{Convert.ToBase64String(bytes)}",
|
|
56
|
+
alt = Path.GetFileNameWithoutExtension(dialog.FileName),
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
public async Task<OpenResult> OpenAsync(string? path)
|
|
61
|
+
{
|
|
62
|
+
var source = RequirePath(path);
|
|
63
|
+
if (!File.Exists(source)) throw new FileNotFoundException("File not found.", source);
|
|
64
|
+
var ext = Path.GetExtension(source).ToLowerInvariant();
|
|
65
|
+
if (ext is ".md" or ".markdown")
|
|
66
|
+
{
|
|
67
|
+
return new OpenResult(source, source, "markdown", await File.ReadAllTextAsync(source));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (ext is not ".docx" and not ".pptx" and not ".ppt")
|
|
71
|
+
{
|
|
72
|
+
throw new InvalidOperationException($"Unsupported file type: {ext}");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
var outDir = Path.Combine(sessionRoot, Path.GetFileNameWithoutExtension(source) + "-" + Guid.NewGuid().ToString("N")[..8]);
|
|
76
|
+
Directory.CreateDirectory(outDir);
|
|
77
|
+
var report = RunBuildCorpus(source, "--out", outDir);
|
|
78
|
+
var output = report.RootElement.GetProperty("outputs")[0].GetString();
|
|
79
|
+
if (string.IsNullOrWhiteSpace(output) || !File.Exists(output))
|
|
80
|
+
{
|
|
81
|
+
throw new InvalidOperationException("Build Corpus did not produce a Markdown file.");
|
|
82
|
+
}
|
|
83
|
+
return new OpenResult(source, output, ext.TrimStart('.'), await File.ReadAllTextAsync(output));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
public SaveResult Save(string? path, string content)
|
|
87
|
+
{
|
|
88
|
+
var target = RequirePath(path);
|
|
89
|
+
if (Path.GetExtension(target).ToLowerInvariant() is not ".md" and not ".markdown")
|
|
90
|
+
{
|
|
91
|
+
target = Path.ChangeExtension(target, ".md");
|
|
92
|
+
}
|
|
93
|
+
Directory.CreateDirectory(Path.GetDirectoryName(target)!);
|
|
94
|
+
File.WriteAllText(target, content);
|
|
95
|
+
return new SaveResult(target);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
public async Task<DocumentSelfTestResult> RunDocumentSelfTestAsync(string? inputPath, string? outputDir)
|
|
99
|
+
{
|
|
100
|
+
var source = RequirePath(inputPath);
|
|
101
|
+
var destination = string.IsNullOrWhiteSpace(outputDir)
|
|
102
|
+
? Path.Combine(sessionRoot, "document-self-test-" + Guid.NewGuid().ToString("N")[..8])
|
|
103
|
+
: Path.GetFullPath(outputDir);
|
|
104
|
+
Directory.CreateDirectory(destination);
|
|
105
|
+
|
|
106
|
+
var opened = await OpenAsync(source);
|
|
107
|
+
if (string.IsNullOrWhiteSpace(opened.Content))
|
|
108
|
+
{
|
|
109
|
+
throw new InvalidOperationException("Opened document was empty.");
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
var marker = $"regen.mde functional edit {DateTimeOffset.UtcNow:yyyyMMddHHmmss}";
|
|
113
|
+
var edited = opened.Content.TrimEnd() + Environment.NewLine + Environment.NewLine + marker + Environment.NewLine;
|
|
114
|
+
var savedMarkdown = Path.Combine(destination, Path.GetFileNameWithoutExtension(source) + ".edited.md");
|
|
115
|
+
var save = Save(savedMarkdown, edited);
|
|
116
|
+
if (!File.ReadAllText(save.Output).Contains(marker, StringComparison.Ordinal))
|
|
117
|
+
{
|
|
118
|
+
throw new InvalidOperationException("Saved Markdown did not contain the edit marker.");
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
var exportedWord = Path.Combine(destination, Path.GetFileNameWithoutExtension(source) + ".edited.docx");
|
|
122
|
+
await ExportWordAsync(exportedWord, edited);
|
|
123
|
+
if (!File.Exists(exportedWord) || new FileInfo(exportedWord).Length == 0)
|
|
124
|
+
{
|
|
125
|
+
throw new InvalidOperationException("Word export was missing or empty.");
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
var reconvertDir = Path.Combine(destination, "reconverted");
|
|
129
|
+
Directory.CreateDirectory(reconvertDir);
|
|
130
|
+
var report = RunBuildCorpus(exportedWord, "--out", reconvertDir);
|
|
131
|
+
var reconvertedMarkdown = report.RootElement.GetProperty("outputs")[0].GetString();
|
|
132
|
+
if (string.IsNullOrWhiteSpace(reconvertedMarkdown) || !File.Exists(reconvertedMarkdown))
|
|
133
|
+
{
|
|
134
|
+
throw new InvalidOperationException("Exported Word document did not reconvert to Markdown.");
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
var reconvertedText = await File.ReadAllTextAsync(reconvertedMarkdown);
|
|
138
|
+
if (!reconvertedText.Contains("regen.mde functional edit", StringComparison.Ordinal))
|
|
139
|
+
{
|
|
140
|
+
throw new InvalidOperationException("Reconverted Markdown did not contain the edit marker.");
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
return new DocumentSelfTestResult(
|
|
144
|
+
source,
|
|
145
|
+
opened.WorkingPath,
|
|
146
|
+
save.Output,
|
|
147
|
+
exportedWord,
|
|
148
|
+
reconvertedMarkdown,
|
|
149
|
+
marker);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
public async Task<SaveResult?> SaveAsAsync(string? suggestedPath, string format, string content)
|
|
153
|
+
{
|
|
154
|
+
using var dialog = new SaveFileDialog
|
|
155
|
+
{
|
|
156
|
+
Title = format == "word" ? "Export Word Document" : "Save Markdown",
|
|
157
|
+
Filter = format == "word" ? "Word document|*.docx" : "Markdown|*.md",
|
|
158
|
+
FileName = SuggestedFileName(suggestedPath, format == "word" ? ".docx" : ".md"),
|
|
159
|
+
AddExtension = true,
|
|
160
|
+
OverwritePrompt = true,
|
|
161
|
+
};
|
|
162
|
+
if (dialog.ShowDialog() != DialogResult.OK) return null;
|
|
163
|
+
|
|
164
|
+
if (format == "word")
|
|
165
|
+
{
|
|
166
|
+
return new SaveResult(await ExportWordAsync(dialog.FileName, content));
|
|
167
|
+
}
|
|
168
|
+
File.WriteAllText(dialog.FileName, content);
|
|
169
|
+
return new SaveResult(dialog.FileName);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
public async Task<SaveResult> SaveAsDirectAsync(string? targetPath, string format, string content)
|
|
173
|
+
{
|
|
174
|
+
var target = RequirePath(targetPath);
|
|
175
|
+
Directory.CreateDirectory(Path.GetDirectoryName(target)!);
|
|
176
|
+
if (format == "word")
|
|
177
|
+
{
|
|
178
|
+
return new SaveResult(await ExportWordAsync(target, content));
|
|
179
|
+
}
|
|
180
|
+
if (Path.GetExtension(target).ToLowerInvariant() is not ".md" and not ".markdown")
|
|
181
|
+
{
|
|
182
|
+
target = Path.ChangeExtension(target, ".md");
|
|
183
|
+
}
|
|
184
|
+
await File.WriteAllTextAsync(target, content);
|
|
185
|
+
return new SaveResult(target);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
private async Task<string> ExportWordAsync(string targetPath, string content)
|
|
189
|
+
{
|
|
190
|
+
var tmp = Path.Combine(sessionRoot, "export-" + Guid.NewGuid().ToString("N"));
|
|
191
|
+
Directory.CreateDirectory(tmp);
|
|
192
|
+
var md = Path.Combine(tmp, Path.GetFileNameWithoutExtension(targetPath) + ".md");
|
|
193
|
+
await File.WriteAllTextAsync(md, content);
|
|
194
|
+
RunBuildCorpus(md, "--to", "word", "--out-same-dir");
|
|
195
|
+
var generated = Path.ChangeExtension(md, ".docx");
|
|
196
|
+
File.Copy(generated, targetPath, overwrite: true);
|
|
197
|
+
return targetPath;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
private JsonDocument RunBuildCorpus(params string[] args)
|
|
201
|
+
{
|
|
202
|
+
var psi = new ProcessStartInfo
|
|
203
|
+
{
|
|
204
|
+
FileName = "node",
|
|
205
|
+
WorkingDirectory = root,
|
|
206
|
+
RedirectStandardOutput = true,
|
|
207
|
+
RedirectStandardError = true,
|
|
208
|
+
UseShellExecute = false,
|
|
209
|
+
};
|
|
210
|
+
psi.ArgumentList.Add(Path.Combine(root, "bin", "build-corpus.js"));
|
|
211
|
+
foreach (var arg in args) psi.ArgumentList.Add(arg);
|
|
212
|
+
psi.Environment["PYTHONPATH"] = Path.Combine(root, "src");
|
|
213
|
+
|
|
214
|
+
using var process = Process.Start(psi) ?? throw new InvalidOperationException("Could not start build-corpus.");
|
|
215
|
+
var stdout = process.StandardOutput.ReadToEnd();
|
|
216
|
+
var stderr = process.StandardError.ReadToEnd();
|
|
217
|
+
process.WaitForExit();
|
|
218
|
+
if (process.ExitCode != 0)
|
|
219
|
+
{
|
|
220
|
+
throw new InvalidOperationException(stderr.Length > 0 ? stderr : stdout);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
var start = stdout.IndexOf('{');
|
|
224
|
+
var end = stdout.LastIndexOf('}');
|
|
225
|
+
if (start < 0 || end < start) throw new InvalidOperationException("Build Corpus did not return JSON.");
|
|
226
|
+
return JsonDocument.Parse(stdout[start..(end + 1)]);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
private static string RequirePath(string? path)
|
|
230
|
+
{
|
|
231
|
+
if (string.IsNullOrWhiteSpace(path)) throw new InvalidOperationException("Missing path.");
|
|
232
|
+
return Path.GetFullPath(path);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
private static string SuggestedFileName(string? path, string extension)
|
|
236
|
+
{
|
|
237
|
+
if (string.IsNullOrWhiteSpace(path)) return "document" + extension;
|
|
238
|
+
return Path.ChangeExtension(Path.GetFileName(path), extension);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
private static string LocateRoot()
|
|
242
|
+
{
|
|
243
|
+
var env = Environment.GetEnvironmentVariable("BUILD_CORPUS_ROOT");
|
|
244
|
+
if (!string.IsNullOrWhiteSpace(env) && File.Exists(Path.Combine(env, "bin", "build-corpus.js")))
|
|
245
|
+
{
|
|
246
|
+
return Path.GetFullPath(env);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
var current = AppContext.BaseDirectory;
|
|
250
|
+
while (!string.IsNullOrWhiteSpace(current))
|
|
251
|
+
{
|
|
252
|
+
if (File.Exists(Path.Combine(current, "bin", "build-corpus.js"))) return current;
|
|
253
|
+
var parent = Directory.GetParent(current)?.FullName;
|
|
254
|
+
if (parent == current) break;
|
|
255
|
+
current = parent ?? "";
|
|
256
|
+
}
|
|
257
|
+
return Directory.GetCurrentDirectory();
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
internal sealed record StartupResult(string? InitialPath);
|
|
262
|
+
internal sealed record OpenResult(string SourcePath, string WorkingPath, string OriginalFormat, string Content);
|
|
263
|
+
internal sealed record SaveResult(string Output);
|
|
264
|
+
internal sealed record DocumentSelfTestResult(
|
|
265
|
+
string SourcePath,
|
|
266
|
+
string WorkingPath,
|
|
267
|
+
string SavedMarkdown,
|
|
268
|
+
string ExportedWord,
|
|
269
|
+
string ReconvertedMarkdown,
|
|
270
|
+
string Marker);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<Project Sdk="Microsoft.NET.Sdk">
|
|
2
|
+
<PropertyGroup>
|
|
3
|
+
<OutputType>WinExe</OutputType>
|
|
4
|
+
<TargetFramework>net8.0-windows</TargetFramework>
|
|
5
|
+
<UseWindowsForms>true</UseWindowsForms>
|
|
6
|
+
<Nullable>enable</Nullable>
|
|
7
|
+
<ImplicitUsings>enable</ImplicitUsings>
|
|
8
|
+
<ApplicationManifest>app.manifest</ApplicationManifest>
|
|
9
|
+
<AssemblyName>BuildCorpusEditor</AssemblyName>
|
|
10
|
+
<RootNamespace>BuildCorpusEditor</RootNamespace>
|
|
11
|
+
</PropertyGroup>
|
|
12
|
+
|
|
13
|
+
<ItemGroup>
|
|
14
|
+
<PackageReference Include="Microsoft.Web.WebView2" Version="1.0.3537.50" />
|
|
15
|
+
</ItemGroup>
|
|
16
|
+
|
|
17
|
+
<ItemGroup>
|
|
18
|
+
<Content Include="wwwroot\**\*">
|
|
19
|
+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
|
20
|
+
</Content>
|
|
21
|
+
</ItemGroup>
|
|
22
|
+
</Project>
|