dimcode-darwin-x64 0.1.2-beta.1 → 0.1.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.
Files changed (148) hide show
  1. package/bin/dimcode +0 -0
  2. package/package.json +1 -1
  3. package/bin/runtime/sandbox/dim-sandbox-runner +0 -0
  4. package/bin/runtime/sandbox/manifest.json +0 -15
  5. package/bin/skills-assets/deep-investigate/SKILL.md +0 -101
  6. package/bin/skills-assets/deep-investigate/references/prompts.md +0 -75
  7. package/bin/skills-assets/deep-investigate/references/templates.md +0 -73
  8. package/bin/skills-assets/deep-investigate/references/thinking-tools.md +0 -36
  9. package/bin/skills-assets/docs-sprint/SKILL.md +0 -73
  10. package/bin/skills-assets/docs-sprint/agents/openai.yaml +0 -4
  11. package/bin/skills-assets/docs-sprint/references/contract-discipline.md +0 -30
  12. package/bin/skills-assets/docs-sprint/references/delivery-plan.md +0 -162
  13. package/bin/skills-assets/docs-sprint/references/documentation-system.md +0 -109
  14. package/bin/skills-assets/docs-sprint/references/ui-layout.md +0 -73
  15. package/bin/skills-assets/docs-sprint/references/worktree-guide.md +0 -45
  16. package/bin/skills-assets/docx/SKILL.md +0 -273
  17. package/bin/skills-assets/docx/assets/styles/academic_styles.xml +0 -250
  18. package/bin/skills-assets/docx/assets/styles/corporate_styles.xml +0 -284
  19. package/bin/skills-assets/docx/assets/styles/default_styles.xml +0 -449
  20. package/bin/skills-assets/docx/assets/xsd/aesthetic-rules.xsd +0 -470
  21. package/bin/skills-assets/docx/assets/xsd/business-rules.xsd +0 -130
  22. package/bin/skills-assets/docx/assets/xsd/common-types.xsd +0 -159
  23. package/bin/skills-assets/docx/assets/xsd/wml-subset.xsd +0 -589
  24. package/bin/skills-assets/docx/references/cjk_typography.md +0 -357
  25. package/bin/skills-assets/docx/references/cjk_university_template_guide.md +0 -184
  26. package/bin/skills-assets/docx/references/comments_guide.md +0 -191
  27. package/bin/skills-assets/docx/references/design_good_bad_examples.md +0 -829
  28. package/bin/skills-assets/docx/references/design_principles.md +0 -819
  29. package/bin/skills-assets/docx/references/openxml_element_order.md +0 -308
  30. package/bin/skills-assets/docx/references/openxml_encyclopedia_part1.md +0 -4061
  31. package/bin/skills-assets/docx/references/openxml_encyclopedia_part2.md +0 -2820
  32. package/bin/skills-assets/docx/references/openxml_encyclopedia_part3.md +0 -3381
  33. package/bin/skills-assets/docx/references/openxml_namespaces.md +0 -82
  34. package/bin/skills-assets/docx/references/openxml_units.md +0 -72
  35. package/bin/skills-assets/docx/references/scenario_a_create.md +0 -284
  36. package/bin/skills-assets/docx/references/scenario_b_edit_content.md +0 -295
  37. package/bin/skills-assets/docx/references/scenario_c_apply_template.md +0 -456
  38. package/bin/skills-assets/docx/references/track_changes_guide.md +0 -200
  39. package/bin/skills-assets/docx/references/troubleshooting.md +0 -506
  40. package/bin/skills-assets/docx/references/typography_guide.md +0 -294
  41. package/bin/skills-assets/docx/references/xsd_validation_guide.md +0 -158
  42. package/bin/skills-assets/docx/scripts/doc_to_docx.sh +0 -40
  43. package/bin/skills-assets/docx/scripts/docx_preview.sh +0 -37
  44. package/bin/skills-assets/docx/scripts/dotnet/Docx.Cli/Docx.Cli.csproj +0 -19
  45. package/bin/skills-assets/docx/scripts/dotnet/Docx.Cli/Program.cs +0 -18
  46. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/Commands/AnalyzeCommand.cs +0 -147
  47. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/Commands/ApplyTemplateCommand.cs +0 -322
  48. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/Commands/CreateCommand.cs +0 -324
  49. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/Commands/DiffCommand.cs +0 -155
  50. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/Commands/EditContentCommand.cs +0 -487
  51. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/Commands/FixOrderCommand.cs +0 -108
  52. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/Commands/MergeRunsCommand.cs +0 -122
  53. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/Commands/ValidateCommand.cs +0 -107
  54. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/Docx.Core.csproj +0 -15
  55. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/OpenXml/CommentSynchronizer.cs +0 -169
  56. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/OpenXml/ElementOrder.cs +0 -80
  57. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/OpenXml/NamespaceConstants.cs +0 -42
  58. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/OpenXml/RunMerger.cs +0 -81
  59. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/OpenXml/StyleAnalyzer.cs +0 -81
  60. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/OpenXml/TrackChangesHelper.cs +0 -99
  61. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/OpenXml/UnitConverter.cs +0 -23
  62. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/Samples/AestheticRecipeSamples.cs +0 -1832
  63. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/Samples/AestheticRecipeSamples_Batch1.cs +0 -910
  64. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/Samples/AestheticRecipeSamples_Batch2.cs +0 -999
  65. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/Samples/AestheticRecipeSamples_Batch3.cs +0 -1048
  66. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/Samples/AestheticRecipeSamples_Batch4.cs +0 -1038
  67. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/Samples/CharacterFormattingSamples.cs +0 -1020
  68. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/Samples/DocumentCreationSamples.cs +0 -1121
  69. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/Samples/FieldAndTocSamples.cs +0 -624
  70. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/Samples/FootnoteAndCommentSamples.cs +0 -675
  71. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/Samples/HeaderFooterSamples.cs +0 -838
  72. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/Samples/ImageSamples.cs +0 -917
  73. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/Samples/ListAndNumberingSamples.cs +0 -826
  74. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/Samples/ParagraphFormattingSamples.cs +0 -1199
  75. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/Samples/StyleSystemSamples.cs +0 -1487
  76. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/Samples/TableSamples.cs +0 -1163
  77. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/Samples/TrackChangesSamples.cs +0 -595
  78. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/Typography/CjkHelper.cs +0 -39
  79. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/Typography/FontDefaults.cs +0 -24
  80. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/Typography/PageSizes.cs +0 -20
  81. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/Validation/BusinessRuleValidator.cs +0 -224
  82. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/Validation/GateCheckValidator.cs +0 -148
  83. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/Validation/ValidationResult.cs +0 -23
  84. package/bin/skills-assets/docx/scripts/dotnet/Docx.Core/Validation/XsdValidator.cs +0 -69
  85. package/bin/skills-assets/docx/scripts/dotnet/Docx.slnx +0 -4
  86. package/bin/skills-assets/docx/scripts/env_check.sh +0 -196
  87. package/bin/skills-assets/docx/scripts/setup.ps1 +0 -274
  88. package/bin/skills-assets/docx/scripts/setup.sh +0 -504
  89. package/bin/skills-assets/pdf/README.md +0 -222
  90. package/bin/skills-assets/pdf/SKILL.md +0 -191
  91. package/bin/skills-assets/pdf/design/design.md +0 -381
  92. package/bin/skills-assets/pdf/scripts/cover.py +0 -1579
  93. package/bin/skills-assets/pdf/scripts/fill_inspect.py +0 -200
  94. package/bin/skills-assets/pdf/scripts/fill_write.py +0 -242
  95. package/bin/skills-assets/pdf/scripts/make.sh +0 -491
  96. package/bin/skills-assets/pdf/scripts/merge.py +0 -112
  97. package/bin/skills-assets/pdf/scripts/palette.py +0 -521
  98. package/bin/skills-assets/pdf/scripts/reformat_parse.py +0 -374
  99. package/bin/skills-assets/pdf/scripts/render_body.py +0 -1052
  100. package/bin/skills-assets/pdf/scripts/render_cover.js +0 -111
  101. package/bin/skills-assets/pptx-generator/SKILL.md +0 -248
  102. package/bin/skills-assets/pptx-generator/references/design-system.md +0 -392
  103. package/bin/skills-assets/pptx-generator/references/editing.md +0 -162
  104. package/bin/skills-assets/pptx-generator/references/pitfalls.md +0 -112
  105. package/bin/skills-assets/pptx-generator/references/pptxgenjs.md +0 -420
  106. package/bin/skills-assets/pptx-generator/references/slide-types.md +0 -413
  107. package/bin/skills-assets/skill-creator/SKILL.md +0 -368
  108. package/bin/skills-assets/skill-creator/agents/openai.yaml +0 -5
  109. package/bin/skills-assets/skill-creator/assets/skill-creator-small.svg +0 -3
  110. package/bin/skills-assets/skill-creator/assets/skill-creator.png +0 -0
  111. package/bin/skills-assets/skill-creator/license.txt +0 -202
  112. package/bin/skills-assets/skill-creator/references/openai_yaml.md +0 -49
  113. package/bin/skills-assets/skill-creator/scripts/generate_openai_yaml.py +0 -226
  114. package/bin/skills-assets/skill-creator/scripts/init_skill.py +0 -397
  115. package/bin/skills-assets/skill-creator/scripts/quick_validate.py +0 -101
  116. package/bin/skills-assets/skill-installer/LICENSE.txt +0 -202
  117. package/bin/skills-assets/skill-installer/SKILL.md +0 -58
  118. package/bin/skills-assets/skill-installer/agents/openai.yaml +0 -5
  119. package/bin/skills-assets/skill-installer/assets/skill-installer-small.svg +0 -3
  120. package/bin/skills-assets/skill-installer/assets/skill-installer.png +0 -0
  121. package/bin/skills-assets/skill-installer/scripts/github_utils.py +0 -21
  122. package/bin/skills-assets/skill-installer/scripts/install-skill-from-github.py +0 -308
  123. package/bin/skills-assets/skill-installer/scripts/list-skills.py +0 -107
  124. package/bin/skills-assets/xlsx/SKILL.md +0 -137
  125. package/bin/skills-assets/xlsx/references/create.md +0 -691
  126. package/bin/skills-assets/xlsx/references/edit.md +0 -684
  127. package/bin/skills-assets/xlsx/references/fix.md +0 -37
  128. package/bin/skills-assets/xlsx/references/format.md +0 -768
  129. package/bin/skills-assets/xlsx/references/ooxml-cheatsheet.md +0 -231
  130. package/bin/skills-assets/xlsx/references/read-analyze.md +0 -97
  131. package/bin/skills-assets/xlsx/references/validate.md +0 -772
  132. package/bin/skills-assets/xlsx/scripts/formula_check.py +0 -422
  133. package/bin/skills-assets/xlsx/scripts/libreoffice_recalc.py +0 -248
  134. package/bin/skills-assets/xlsx/scripts/shared_strings_builder.py +0 -163
  135. package/bin/skills-assets/xlsx/scripts/style_audit.py +0 -575
  136. package/bin/skills-assets/xlsx/scripts/xlsx_add_column.py +0 -395
  137. package/bin/skills-assets/xlsx/scripts/xlsx_insert_row.py +0 -274
  138. package/bin/skills-assets/xlsx/scripts/xlsx_pack.py +0 -87
  139. package/bin/skills-assets/xlsx/scripts/xlsx_reader.py +0 -362
  140. package/bin/skills-assets/xlsx/scripts/xlsx_shift_rows.py +0 -396
  141. package/bin/skills-assets/xlsx/scripts/xlsx_unpack.py +0 -130
  142. package/bin/skills-assets/xlsx/templates/minimal_xlsx/[Content_Types].xml +0 -9
  143. package/bin/skills-assets/xlsx/templates/minimal_xlsx/_rels/.rels +0 -6
  144. package/bin/skills-assets/xlsx/templates/minimal_xlsx/xl/_rels/workbook.xml.rels +0 -19
  145. package/bin/skills-assets/xlsx/templates/minimal_xlsx/xl/sharedStrings.xml +0 -33
  146. package/bin/skills-assets/xlsx/templates/minimal_xlsx/xl/styles.xml +0 -160
  147. package/bin/skills-assets/xlsx/templates/minimal_xlsx/xl/workbook.xml +0 -30
  148. package/bin/skills-assets/xlsx/templates/minimal_xlsx/xl/worksheets/sheet1.xml +0 -70
@@ -1,487 +0,0 @@
1
- using System.CommandLine;
2
- using System.Text.RegularExpressions;
3
- using DocumentFormat.OpenXml;
4
- using DocumentFormat.OpenXml.Packaging;
5
- using DocumentFormat.OpenXml.Wordprocessing;
6
- using Docx.Core.OpenXml;
7
-
8
- namespace Docx.Core.Commands;
9
-
10
- /// <summary>
11
- /// Scenario B: Surgical content editing operations on existing DOCX files.
12
- /// Preserves all existing formatting and minimizes XML changes.
13
- /// </summary>
14
- public static class EditContentCommand
15
- {
16
- public static Command Create()
17
- {
18
- var cmd = new Command("edit", "Edit existing DOCX content");
19
-
20
- cmd.Add(CreateReplaceTextCommand());
21
- cmd.Add(CreateFillTableCommand());
22
- cmd.Add(CreateInsertParagraphCommand());
23
- cmd.Add(CreateUpdateFieldCommand());
24
- cmd.Add(CreateListPlaceholdersCommand());
25
- cmd.Add(CreateFillPlaceholdersCommand());
26
-
27
- return cmd;
28
- }
29
-
30
- private static Command CreateReplaceTextCommand()
31
- {
32
- var inputOpt = new Option<string>("--input") { Description = "Input DOCX file", Required = true };
33
- var outputOpt = new Option<string>("--output") { Description = "Output file path (defaults to overwriting input)" };
34
- var searchOpt = new Option<string>("--search") { Description = "Text to search for", Required = true };
35
- var replaceOpt = new Option<string>("--replace") { Description = "Replacement text", Required = true };
36
- var regexOpt = new Option<bool>("--regex") { Description = "Treat search as a regex pattern" };
37
-
38
- var cmd = new Command("replace-text", "Replace text while preserving formatting")
39
- {
40
- inputOpt, outputOpt, searchOpt, replaceOpt, regexOpt
41
- };
42
-
43
- cmd.SetAction((parseResult) =>
44
- {
45
- var input = parseResult.GetValue(inputOpt)!;
46
- var output = parseResult.GetValue(outputOpt) ?? input;
47
- var search = parseResult.GetValue(searchOpt)!;
48
- var replace = parseResult.GetValue(replaceOpt)!;
49
- var useRegex = parseResult.GetValue(regexOpt);
50
-
51
- if (output != input) File.Copy(input, output, overwrite: true);
52
-
53
- using var doc = WordprocessingDocument.Open(output, true);
54
- var body = doc.MainDocumentPart?.Document.Body;
55
- if (body == null) { Console.Error.WriteLine("No document body found."); return; }
56
-
57
- int count = 0;
58
- foreach (var paragraph in body.Descendants<Paragraph>())
59
- {
60
- count += ReplaceInParagraph(paragraph, search, replace, useRegex);
61
- }
62
-
63
- doc.MainDocumentPart!.Document.Save();
64
- Console.WriteLine($"Replaced {count} occurrence(s) in {output}");
65
- });
66
-
67
- return cmd;
68
- }
69
-
70
- private static Command CreateFillTableCommand()
71
- {
72
- var inputOpt = new Option<string>("--input") { Description = "Input DOCX file", Required = true };
73
- var outputOpt = new Option<string>("--output") { Description = "Output file path" };
74
- var tableIndexOpt = new Option<int>("--table-index") { Description = "Zero-based index of the table to fill" };
75
- tableIndexOpt.DefaultValueFactory = _ => 0;
76
- var csvOpt = new Option<string>("--csv") { Description = "CSV file with data to fill", Required = true };
77
- var appendOpt = new Option<bool>("--append") { Description = "Append rows instead of replacing existing data rows" };
78
-
79
- var cmd = new Command("fill-table", "Fill a table with data from CSV")
80
- {
81
- inputOpt, outputOpt, tableIndexOpt, csvOpt, appendOpt
82
- };
83
-
84
- cmd.SetAction((parseResult) =>
85
- {
86
- var input = parseResult.GetValue(inputOpt)!;
87
- var output = parseResult.GetValue(outputOpt) ?? input;
88
- var tableIndex = parseResult.GetValue(tableIndexOpt);
89
- var csvPath = parseResult.GetValue(csvOpt)!;
90
- var append = parseResult.GetValue(appendOpt);
91
-
92
- if (output != input) File.Copy(input, output, overwrite: true);
93
-
94
- if (!File.Exists(csvPath)) { Console.Error.WriteLine($"CSV file not found: {csvPath}"); return; }
95
-
96
- using var doc = WordprocessingDocument.Open(output, true);
97
- var body = doc.MainDocumentPart?.Document.Body;
98
- if (body == null) { Console.Error.WriteLine("No document body found."); return; }
99
-
100
- var tables = body.Elements<Table>().ToList();
101
- if (tableIndex >= tables.Count)
102
- {
103
- Console.Error.WriteLine($"Table index {tableIndex} out of range (found {tables.Count} tables).");
104
- return;
105
- }
106
-
107
- var table = tables[tableIndex];
108
- var csvLines = File.ReadAllLines(csvPath);
109
- if (csvLines.Length == 0) { Console.WriteLine("CSV is empty, nothing to fill."); return; }
110
-
111
- // Get template row properties from the first data row (second row, after header)
112
- var existingRows = table.Elements<TableRow>().ToList();
113
- TableRow? templateRow = existingRows.Count > 1 ? existingRows[1] : existingRows.FirstOrDefault();
114
- var templateTrPr = templateRow?.TableRowProperties?.CloneNode(true) as TableRowProperties;
115
-
116
- if (!append)
117
- {
118
- // Remove all rows except the header row
119
- for (int i = existingRows.Count - 1; i >= 1; i--)
120
- existingRows[i].Remove();
121
- }
122
-
123
- int rowsAdded = 0;
124
- // Skip header line in CSV (index 0)
125
- for (int i = 1; i < csvLines.Length; i++)
126
- {
127
- var values = ParseCsvLine(csvLines[i]);
128
- var newRow = new TableRow();
129
- if (templateTrPr != null)
130
- newRow.Append(templateTrPr.CloneNode(true));
131
-
132
- foreach (var val in values)
133
- {
134
- var cell = new TableCell(
135
- new Paragraph(new Run(new Text(val))));
136
- newRow.Append(cell);
137
- }
138
-
139
- table.Append(newRow);
140
- rowsAdded++;
141
- }
142
-
143
- doc.MainDocumentPart!.Document.Save();
144
- Console.WriteLine($"Added {rowsAdded} rows to table {tableIndex} in {output}");
145
- });
146
-
147
- return cmd;
148
- }
149
-
150
- private static Command CreateInsertParagraphCommand()
151
- {
152
- var inputOpt = new Option<string>("--input") { Description = "Input DOCX file", Required = true };
153
- var outputOpt = new Option<string>("--output") { Description = "Output file path" };
154
- var textOpt = new Option<string>("--text") { Description = "Paragraph text", Required = true };
155
- var styleOpt = new Option<string>("--style") { Description = "Paragraph style (e.g. Heading1, Normal)" };
156
- var afterOpt = new Option<int>("--after-paragraph") { Description = "Insert after this paragraph index (0-based)" };
157
- afterOpt.DefaultValueFactory = _ => -1; // -1 = append at end
158
-
159
- var cmd = new Command("insert-paragraph", "Insert a new paragraph")
160
- {
161
- inputOpt, outputOpt, textOpt, styleOpt, afterOpt
162
- };
163
-
164
- cmd.SetAction((parseResult) =>
165
- {
166
- var input = parseResult.GetValue(inputOpt)!;
167
- var output = parseResult.GetValue(outputOpt) ?? input;
168
- var text = parseResult.GetValue(textOpt)!;
169
- var style = parseResult.GetValue(styleOpt);
170
- var afterIndex = parseResult.GetValue(afterOpt);
171
-
172
- if (output != input) File.Copy(input, output, overwrite: true);
173
-
174
- using var doc = WordprocessingDocument.Open(output, true);
175
- var body = doc.MainDocumentPart?.Document.Body;
176
- if (body == null) { Console.Error.WriteLine("No document body found."); return; }
177
-
178
- var newPara = new Paragraph();
179
- if (!string.IsNullOrEmpty(style))
180
- newPara.Append(new ParagraphProperties(new ParagraphStyleId { Val = style }));
181
- newPara.Append(new Run(new Text(text)));
182
-
183
- var paragraphs = body.Elements<Paragraph>().ToList();
184
- if (afterIndex >= 0 && afterIndex < paragraphs.Count)
185
- {
186
- paragraphs[afterIndex].InsertAfterSelf(newPara);
187
- }
188
- else
189
- {
190
- // Insert before sectPr if present, otherwise append
191
- var sectPr = body.Elements<SectionProperties>().FirstOrDefault();
192
- if (sectPr != null)
193
- sectPr.InsertBeforeSelf(newPara);
194
- else
195
- body.Append(newPara);
196
- }
197
-
198
- doc.MainDocumentPart!.Document.Save();
199
- Console.WriteLine($"Inserted paragraph in {output}");
200
- });
201
-
202
- return cmd;
203
- }
204
-
205
- private static Command CreateUpdateFieldCommand()
206
- {
207
- var inputOpt = new Option<string>("--input") { Description = "Input DOCX file", Required = true };
208
- var outputOpt = new Option<string>("--output") { Description = "Output file path" };
209
- var fieldNameOpt = new Option<string>("--field") { Description = "Document property field name (e.g. TITLE, AUTHOR)", Required = true };
210
- var valueOpt = new Option<string>("--value") { Description = "New field value", Required = true };
211
-
212
- var cmd = new Command("update-field", "Update a document property field value")
213
- {
214
- inputOpt, outputOpt, fieldNameOpt, valueOpt
215
- };
216
-
217
- cmd.SetAction((parseResult) =>
218
- {
219
- var input = parseResult.GetValue(inputOpt)!;
220
- var output = parseResult.GetValue(outputOpt) ?? input;
221
- var fieldName = parseResult.GetValue(fieldNameOpt)!;
222
- var value = parseResult.GetValue(valueOpt)!;
223
-
224
- if (output != input) File.Copy(input, output, overwrite: true);
225
-
226
- using var doc = WordprocessingDocument.Open(output, true);
227
-
228
- // Update core properties
229
- var props = doc.PackageProperties;
230
- switch (fieldName.ToUpperInvariant())
231
- {
232
- case "TITLE": props.Title = value; break;
233
- case "AUTHOR": props.Creator = value; break;
234
- case "SUBJECT": props.Subject = value; break;
235
- case "KEYWORDS": props.Keywords = value; break;
236
- case "DESCRIPTION": props.Description = value; break;
237
- case "CATEGORY": props.Category = value; break;
238
- default:
239
- Console.Error.WriteLine($"Unknown field: {fieldName}. Supported: TITLE, AUTHOR, SUBJECT, KEYWORDS, DESCRIPTION, CATEGORY");
240
- return;
241
- }
242
-
243
- Console.WriteLine($"Updated {fieldName} to \"{value}\" in {output}");
244
- });
245
-
246
- return cmd;
247
- }
248
-
249
- private static Command CreateListPlaceholdersCommand()
250
- {
251
- var inputOpt = new Option<string>("--input") { Description = "Input DOCX file", Required = true };
252
- var patternOpt = new Option<string>("--pattern") { Description = "Placeholder pattern (regex)" };
253
- patternOpt.DefaultValueFactory = _ => @"\{\{(\w+)\}\}"; // {{PLACEHOLDER}}
254
-
255
- var cmd = new Command("list-placeholders", "List all placeholders found in the document")
256
- {
257
- inputOpt, patternOpt
258
- };
259
-
260
- cmd.SetAction((parseResult) =>
261
- {
262
- var input = parseResult.GetValue(inputOpt)!;
263
- var pattern = parseResult.GetValue(patternOpt)!;
264
-
265
- using var doc = WordprocessingDocument.Open(input, false);
266
- var body = doc.MainDocumentPart?.Document.Body;
267
- if (body == null) { Console.Error.WriteLine("No document body found."); return; }
268
-
269
- var placeholders = new HashSet<string>();
270
- var regex = new Regex(pattern);
271
-
272
- foreach (var paragraph in body.Descendants<Paragraph>())
273
- {
274
- var fullText = string.Concat(paragraph.Descendants<Text>().Select(t => t.Text));
275
- foreach (Match match in regex.Matches(fullText))
276
- {
277
- placeholders.Add(match.Value);
278
- }
279
- }
280
-
281
- if (placeholders.Count == 0)
282
- {
283
- Console.WriteLine("No placeholders found.");
284
- return;
285
- }
286
-
287
- Console.WriteLine($"Found {placeholders.Count} unique placeholder(s):");
288
- foreach (var p in placeholders.OrderBy(x => x))
289
- Console.WriteLine($" {p}");
290
- });
291
-
292
- return cmd;
293
- }
294
-
295
- private static Command CreateFillPlaceholdersCommand()
296
- {
297
- var inputOpt = new Option<string>("--input") { Description = "Input DOCX file", Required = true };
298
- var outputOpt = new Option<string>("--output") { Description = "Output file path" };
299
- var mappingOpt = new Option<string>("--mapping") { Description = "JSON file mapping placeholder names to values", Required = true };
300
- var patternOpt = new Option<string>("--pattern") { Description = "Placeholder pattern with capture group for the name" };
301
- patternOpt.DefaultValueFactory = _ => @"\{\{(\w+)\}\}";
302
-
303
- var cmd = new Command("fill-placeholders", "Replace placeholders with values from a mapping file")
304
- {
305
- inputOpt, outputOpt, mappingOpt, patternOpt
306
- };
307
-
308
- cmd.SetAction((parseResult) =>
309
- {
310
- var input = parseResult.GetValue(inputOpt)!;
311
- var output = parseResult.GetValue(outputOpt) ?? input;
312
- var mappingPath = parseResult.GetValue(mappingOpt)!;
313
- var pattern = parseResult.GetValue(patternOpt)!;
314
-
315
- if (!File.Exists(mappingPath)) { Console.Error.WriteLine($"Mapping file not found: {mappingPath}"); return; }
316
-
317
- var mappingJson = File.ReadAllText(mappingPath);
318
- Dictionary<string, string> mapping;
319
- try
320
- {
321
- mapping = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, string>>(mappingJson) ?? [];
322
- }
323
- catch (System.Text.Json.JsonException ex)
324
- {
325
- Console.Error.WriteLine($"Invalid mapping JSON: {ex.Message}");
326
- return;
327
- }
328
-
329
- if (output != input) File.Copy(input, output, overwrite: true);
330
-
331
- using var doc = WordprocessingDocument.Open(output, true);
332
- var body = doc.MainDocumentPart?.Document.Body;
333
- if (body == null) { Console.Error.WriteLine("No document body found."); return; }
334
-
335
- int totalReplacements = 0;
336
- var regex = new Regex(pattern);
337
-
338
- foreach (var paragraph in body.Descendants<Paragraph>())
339
- {
340
- var fullText = string.Concat(paragraph.Descendants<Text>().Select(t => t.Text));
341
- var matches = regex.Matches(fullText);
342
- if (matches.Count == 0) continue;
343
-
344
- foreach (Match match in matches)
345
- {
346
- var placeholderName = match.Groups.Count > 1 ? match.Groups[1].Value : match.Value;
347
- if (mapping.TryGetValue(placeholderName, out var replacement))
348
- {
349
- totalReplacements += ReplaceInParagraph(paragraph, match.Value, replacement, false);
350
- }
351
- }
352
- }
353
-
354
- doc.MainDocumentPart!.Document.Save();
355
- Console.WriteLine($"Filled {totalReplacements} placeholder(s) in {output}");
356
- });
357
-
358
- return cmd;
359
- }
360
-
361
- /// <summary>
362
- /// Replaces text within a paragraph while preserving run formatting.
363
- /// Handles the case where search text may span multiple runs.
364
- /// </summary>
365
- private static int ReplaceInParagraph(Paragraph paragraph, string search, string replace, bool useRegex)
366
- {
367
- var runs = paragraph.Elements<Run>().ToList();
368
- if (runs.Count == 0) return 0;
369
-
370
- // Build the full paragraph text and a map from character index to (run, position within run)
371
- var fullText = string.Concat(runs.SelectMany(r => r.Elements<Text>().Select(t => t.Text)));
372
- if (string.IsNullOrEmpty(fullText)) return 0;
373
-
374
- int count = 0;
375
-
376
- if (!useRegex)
377
- {
378
- // Simple case: search within each run first
379
- foreach (var run in runs)
380
- {
381
- foreach (var textElement in run.Elements<Text>().ToList())
382
- {
383
- if (textElement.Text.Contains(search))
384
- {
385
- var newText = textElement.Text.Replace(search, replace);
386
- count += (textElement.Text.Length - newText.Length + replace.Length - search.Length) == 0 ? 0 :
387
- CountOccurrences(textElement.Text, search);
388
- textElement.Text = newText;
389
- if (newText.StartsWith(' ') || newText.EndsWith(' '))
390
- textElement.Space = SpaceProcessingModeValues.Preserve;
391
- }
392
- }
393
- }
394
-
395
- // Handle cross-run matches by concatenating all runs, replacing, and rebuilding
396
- if (count == 0 && fullText.Contains(search))
397
- {
398
- var newFullText = fullText.Replace(search, replace);
399
- count = CountOccurrences(fullText, search);
400
- RebuildRunsWithText(paragraph, runs, newFullText);
401
- }
402
- }
403
- else
404
- {
405
- var regex = new Regex(search);
406
- if (regex.IsMatch(fullText))
407
- {
408
- count = regex.Matches(fullText).Count;
409
- var newFullText = regex.Replace(fullText, replace);
410
- RebuildRunsWithText(paragraph, runs, newFullText);
411
- }
412
- }
413
-
414
- return count;
415
- }
416
-
417
- /// <summary>
418
- /// Replaces the text content of existing runs with new text,
419
- /// preserving the formatting of the first run.
420
- /// </summary>
421
- private static void RebuildRunsWithText(Paragraph paragraph, List<Run> runs, string newText)
422
- {
423
- if (runs.Count == 0) return;
424
-
425
- // Keep the first run's formatting, set its text to the full new text
426
- var firstRun = runs[0];
427
- var firstText = firstRun.Elements<Text>().FirstOrDefault();
428
- if (firstText != null)
429
- {
430
- firstText.Text = newText;
431
- if (newText.StartsWith(' ') || newText.EndsWith(' '))
432
- firstText.Space = SpaceProcessingModeValues.Preserve;
433
- }
434
-
435
- // Remove all other runs
436
- for (int i = 1; i < runs.Count; i++)
437
- runs[i].Remove();
438
- }
439
-
440
- private static int CountOccurrences(string text, string search)
441
- {
442
- int count = 0;
443
- int index = 0;
444
- while ((index = text.IndexOf(search, index, StringComparison.Ordinal)) != -1)
445
- {
446
- count++;
447
- index += search.Length;
448
- }
449
- return count;
450
- }
451
-
452
- private static string[] ParseCsvLine(string line)
453
- {
454
- // Simple CSV parser (handles quoted fields)
455
- var result = new List<string>();
456
- bool inQuotes = false;
457
- var current = new System.Text.StringBuilder();
458
-
459
- for (int i = 0; i < line.Length; i++)
460
- {
461
- char c = line[i];
462
- if (c == '"')
463
- {
464
- if (inQuotes && i + 1 < line.Length && line[i + 1] == '"')
465
- {
466
- current.Append('"');
467
- i++;
468
- }
469
- else
470
- {
471
- inQuotes = !inQuotes;
472
- }
473
- }
474
- else if (c == ',' && !inQuotes)
475
- {
476
- result.Add(current.ToString());
477
- current.Clear();
478
- }
479
- else
480
- {
481
- current.Append(c);
482
- }
483
- }
484
- result.Add(current.ToString());
485
- return result.ToArray();
486
- }
487
- }
@@ -1,108 +0,0 @@
1
- using System.CommandLine;
2
- using System.IO.Compression;
3
- using System.Xml.Linq;
4
-
5
- namespace Docx.Core.Commands;
6
-
7
- public static class FixOrderCommand
8
- {
9
- private static readonly XNamespace W = "http://schemas.openxmlformats.org/wordprocessingml/2006/main";
10
-
11
- // Canonical element ordering within common parent elements per ISO 29500
12
- private static readonly Dictionary<string, List<string>> ElementOrder = new()
13
- {
14
- ["pPr"] = new() { "pStyle", "keepNext", "keepLines", "pageBreakBefore", "widowControl", "numPr", "suppressLineNumbers", "pBdr", "shd", "tabs", "suppressAutoHyphens", "spacing", "ind", "jc", "outlineLvl", "rPr" },
15
- ["rPr"] = new() { "rStyle", "rFonts", "b", "bCs", "i", "iCs", "caps", "smallCaps", "strike", "dstrike", "vanish", "color", "spacing", "w", "kern", "position", "sz", "szCs", "highlight", "u", "effect", "vertAlign", "lang" },
16
- ["tblPr"] = new() { "tblStyle", "tblpPr", "tblOverlap", "tblW", "jc", "tblInd", "tblBorders", "shd", "tblLayout", "tblCellMar", "tblLook" },
17
- ["tcPr"] = new() { "cnfStyle", "tcW", "gridSpan", "hMerge", "vMerge", "tcBorders", "shd", "noWrap", "tcMar", "textDirection", "tcFitText", "vAlign" },
18
- ["sectPr"] = new() { "headerReference", "footerReference", "footnotePr", "endnotePr", "type", "pgSz", "pgMar", "paperSrc", "pgBorders", "lnNumType", "pgNumType", "cols", "docGrid" },
19
- };
20
-
21
- public static Command Create()
22
- {
23
- var inputOption = new Option<string>("--input") { Description = "DOCX file to fix", Required = true };
24
- var outputOption = new Option<string>("--output") { Description = "Output path (default: overwrite input)" };
25
- var backupOption = new Option<bool>("--backup") { Description = "Create .bak before modifying", DefaultValueFactory = (_) => true };
26
-
27
- var cmd = new Command("fix-order", "Fix OpenXML element ordering per ISO 29500")
28
- {
29
- inputOption, outputOption, backupOption
30
- };
31
-
32
- cmd.SetAction((parseResult) =>
33
- {
34
- var input = parseResult.GetValue(inputOption)!;
35
- var output = parseResult.GetValue(outputOption) ?? input;
36
- var backup = parseResult.GetValue(backupOption);
37
-
38
- if (!File.Exists(input))
39
- {
40
- Console.Error.WriteLine($"File not found: {input}");
41
- return;
42
- }
43
-
44
- if (backup && output == input)
45
- File.Copy(input, input + ".bak", true);
46
-
47
- var tempPath = Path.GetTempFileName();
48
- File.Copy(input, tempPath, true);
49
-
50
- using var zip = ZipFile.Open(tempPath, ZipArchiveMode.Update);
51
- var entry = zip.GetEntry("word/document.xml");
52
- if (entry == null)
53
- {
54
- Console.Error.WriteLine("Not a valid DOCX");
55
- return;
56
- }
57
-
58
- XDocument doc;
59
- using (var stream = entry.Open())
60
- doc = XDocument.Load(stream);
61
-
62
- int reorderedCount = 0;
63
-
64
- foreach (var (parentName, order) in ElementOrder)
65
- {
66
- foreach (var parent in doc.Descendants(W + parentName))
67
- {
68
- var children = parent.Elements().ToList();
69
- var sorted = children.OrderBy(e =>
70
- {
71
- var idx = order.IndexOf(e.Name.LocalName);
72
- return idx >= 0 ? idx : order.Count;
73
- }).ToList();
74
-
75
- bool changed = false;
76
- for (int i = 0; i < children.Count; i++)
77
- {
78
- if (children[i] != sorted[i])
79
- {
80
- changed = true;
81
- break;
82
- }
83
- }
84
-
85
- if (changed)
86
- {
87
- parent.ReplaceNodes(sorted);
88
- reorderedCount++;
89
- }
90
- }
91
- }
92
-
93
- entry.Delete();
94
- var newEntry = zip.CreateEntry("word/document.xml", CompressionLevel.Optimal);
95
- using (var stream = newEntry.Open())
96
- doc.Save(stream);
97
-
98
- zip.Dispose();
99
- File.Copy(tempPath, output, true);
100
- File.Delete(tempPath);
101
-
102
- Console.WriteLine($"Reordered {reorderedCount} element group(s)");
103
- Console.WriteLine($"Written to: {output}");
104
- });
105
-
106
- return cmd;
107
- }
108
- }