aboutsummaryrefslogtreecommitdiff
path: root/src/TablesAndTuples/Program.cs
diff options
context:
space:
mode:
authorRob Mensching <rob@firegiant.com>2018-12-22 09:33:44 -0800
committerRob Mensching <rob@firegiant.com>2018-12-22 09:33:44 -0800
commit229f9f79b7230124b1e270e636608ceaf95a11bc (patch)
treeb653d29b3d1b3aac3eec5d9e198750fad17905e0 /src/TablesAndTuples/Program.cs
parentd08a1f7f46ad7ffe0874133ba20117a7aca0ede4 (diff)
downloadwix-229f9f79b7230124b1e270e636608ceaf95a11bc.tar.gz
wix-229f9f79b7230124b1e270e636608ceaf95a11bc.tar.bz2
wix-229f9f79b7230124b1e270e636608ceaf95a11bc.zip
Quick tool to help convert tables.xml to .cs
Diffstat (limited to 'src/TablesAndTuples/Program.cs')
-rw-r--r--src/TablesAndTuples/Program.cs348
1 files changed, 348 insertions, 0 deletions
diff --git a/src/TablesAndTuples/Program.cs b/src/TablesAndTuples/Program.cs
new file mode 100644
index 00000000..c15c3c6d
--- /dev/null
+++ b/src/TablesAndTuples/Program.cs
@@ -0,0 +1,348 @@
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Linq;
5using System.Text;
6using System.Xml.Linq;
7using SimpleJson;
8
9namespace TablesAndTuples
10{
11 class Program
12 {
13 static readonly XNamespace ns = "http://wixtoolset.org/schemas/v4/wi/tables";
14 static readonly XName TableDefinition = ns + "tableDefinition";
15 static readonly XName ColumnDefinition = ns + "columnDefinition";
16 static readonly XName Name = "name";
17 static readonly XName Type = "type";
18
19 static void Main(string[] args)
20 {
21 if (args.Length == 0)
22 {
23 return;
24 }
25 else if (Path.GetExtension(args[0]) == ".xml")
26 {
27 if (args.Length < 2)
28 {
29 Console.WriteLine("Need to specify output json file as well.");
30 }
31
32 ReadXmlWriteJson(Path.GetFullPath(args[0]), Path.GetFullPath(args[1]));
33 }
34 else if (Path.GetExtension(args[0]) == ".json")
35 {
36 string prefix = null;
37 if (args.Length < 2)
38 {
39 Console.WriteLine("Need to specify output folder.");
40 }
41 else if (args.Length > 2)
42 {
43 prefix = args[2];
44 }
45
46 ReadJsonWriteCs(Path.GetFullPath(args[0]), Path.GetFullPath(args[1]), prefix);
47 }
48 }
49
50 private static void ReadXmlWriteJson(string inputPath, string outputPath)
51 {
52 var doc = XDocument.Load(inputPath);
53
54 var array = new JsonArray();
55
56 foreach (var tableDefinition in doc.Descendants(TableDefinition))
57 {
58 var tupleType = tableDefinition.Attribute(Name).Value;
59
60 var fields = new JsonArray();
61
62 foreach (var columnDefinition in tableDefinition.Elements(ColumnDefinition))
63 {
64 var fieldName = columnDefinition.Attribute(Name).Value;
65 var type = columnDefinition.Attribute(Type).Value;
66
67 if (type == "localized")
68 {
69 type = "string";
70 }
71 else if (type == "object")
72 {
73 type = "path";
74 }
75
76 var field = new JsonObject
77 {
78 { fieldName, type }
79 };
80
81 fields.Add(field);
82 }
83
84 var obj = new JsonObject
85 {
86 { tupleType, fields }
87 };
88 array.Add(obj);
89 }
90
91 array.Sort(CompareTupleDefinitions);
92
93 var strat = new PocoJsonSerializerStrategy();
94 var json = SimpleJson.SimpleJson.SerializeObject(array, strat);
95
96 Directory.CreateDirectory(Path.GetDirectoryName(outputPath));
97 File.WriteAllText(outputPath, json);
98 }
99
100 private static void ReadJsonWriteCs(string inputPath, string outputFolder, string prefix)
101 {
102 var json = File.ReadAllText(inputPath);
103 var tuples = SimpleJson.SimpleJson.DeserializeObject(json) as JsonArray;
104
105 var tupleNames = new List<string>();
106
107 foreach (var tupleDefinition in tuples.Cast<JsonObject>())
108 {
109 var tupleName = tupleDefinition.Keys.Single();
110 var fields = tupleDefinition.Values.Single() as JsonArray;
111
112 var list = GetFields(fields).ToList();
113
114 tupleNames.Add(tupleName);
115
116 var text = GenerateTupleFileText(prefix, tupleName, list);
117
118 var pathTuple = Path.Combine(outputFolder, tupleName + "Tuple.cs");
119 Console.WriteLine("Writing: {0}", pathTuple);
120 File.WriteAllText(pathTuple, text);
121 }
122
123 var content = TupleNamesFileContent(prefix, tupleNames);
124 var pathNames = Path.Combine(outputFolder, String.Concat(prefix, "TupleDefinitions.cs"));
125 Console.WriteLine("Writing: {0}", pathNames);
126 File.WriteAllText(pathNames, content);
127 }
128
129 private static IEnumerable<(string Name, string Type, string ClrType, string AsFunction)> GetFields(JsonArray fields)
130 {
131 foreach (var field in fields.Cast<JsonObject>())
132 {
133 var fieldName = field.Keys.Single();
134 var fieldType = field.Values.Single() as string;
135
136 var clrType = ConvertToClrType(fieldType);
137 fieldType = ConvertToFieldType(fieldType);
138
139 var asFunction = $"As{fieldType}()";
140
141 yield return (Name: fieldName, Type: fieldType, ClrType: clrType, AsFunction: asFunction);
142 }
143 }
144
145 private static string GenerateTupleFileText(string prefix, string tupleName, List<(string Name, string Type, string ClrType, string AsFunction)> tupleFields)
146 {
147 var ns = prefix ?? "Data";
148 var toString = String.IsNullOrEmpty(prefix) ? null : ".ToString()";
149
150 var startTupleDef = String.Join(Environment.NewLine,
151 "// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.",
152 "",
153 "namespace WixToolset.{2}",
154 "{",
155 " using WixToolset.Data;",
156 " using WixToolset.{2}.Tuples;",
157 "",
158 " public static partial class {3}TupleDefinitions",
159 " {",
160 " public static readonly IntermediateTupleDefinition {1} = new IntermediateTupleDefinition(",
161 " {3}TupleDefinitionType.{1}{4},",
162 " new[]",
163 " {");
164 var fieldDef =
165 " new IntermediateFieldDefinition(nameof({1}TupleFields.{2}), IntermediateFieldType.{3}),";
166 var endTupleDef = String.Join(Environment.NewLine,
167 " },",
168 " typeof({1}Tuple));",
169 " }",
170 "}",
171 "",
172 "namespace WixToolset.{2}.Tuples",
173 "{",
174 " using WixToolset.Data;",
175 "",
176 " public enum {1}TupleFields",
177 " {");
178 var fieldEnum =
179 " {2},";
180 var startTuple = String.Join(Environment.NewLine,
181 " }",
182 "",
183 " public class {1}Tuple : IntermediateTuple",
184 " {",
185 " public {1}Tuple() : base({3}TupleDefinitions.{1}, null, null)",
186 " {",
187 " }",
188 "",
189 " public {1}Tuple(SourceLineNumber sourceLineNumber, Identifier id = null) : base({3}TupleDefinitions.{1}, sourceLineNumber, id)",
190 " {",
191 " }",
192 "",
193 " public IntermediateField this[{1}TupleFields index] => this.Fields[(int)index];");
194 var fieldProp = String.Join(Environment.NewLine,
195 "",
196 " public {4} {2}",
197 " {",
198 " get => this.Fields[(int){1}TupleFields.{2}].{5};",
199 " set => this.Set((int){1}TupleFields.{2}, value);",
200 " }");
201 var endTuple = String.Join(Environment.NewLine,
202 " }",
203 "}");
204
205 var sb = new StringBuilder();
206
207 sb.AppendLine(startTupleDef.Replace("{1}", tupleName).Replace("{2}", ns).Replace("{3}", prefix).Replace("{4}", toString));
208 foreach (var field in tupleFields)
209 {
210 sb.AppendLine(fieldDef.Replace("{1}", tupleName).Replace("{2}", field.Name).Replace("{3}", field.Type).Replace("{4}", field.ClrType).Replace("{5}", field.AsFunction));
211 }
212 sb.AppendLine(endTupleDef.Replace("{1}", tupleName).Replace("{2}", ns).Replace("{3}", prefix));
213 foreach (var field in tupleFields)
214 {
215 sb.AppendLine(fieldEnum.Replace("{1}", tupleName).Replace("{2}", field.Name).Replace("{3}", field.Type).Replace("{4}", field.ClrType).Replace("{5}", field.AsFunction));
216 }
217 sb.AppendLine(startTuple.Replace("{1}", tupleName).Replace("{2}", ns).Replace("{3}", prefix));
218 foreach (var field in tupleFields)
219 {
220 sb.AppendLine(fieldProp.Replace("{1}", tupleName).Replace("{2}", field.Name).Replace("{3}", field.Type).Replace("{4}", field.ClrType).Replace("{5}", field.AsFunction));
221 }
222 sb.Append(endTuple);
223
224 return sb.ToString();
225 }
226
227 private static string TupleNamesFileContent(string prefix, List<string> tupleNames)
228 {
229 var ns = prefix ?? "Data";
230
231 var header = String.Join(Environment.NewLine,
232 "// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information.",
233 "",
234 "namespace WixToolset.{2}",
235 "{",
236 " using System;",
237 " using WixToolset.Data;",
238 "",
239 " public enum {3}TupleDefinitionType",
240 " {");
241 var namesFormat =
242 " {1},";
243 var midpoint = String.Join(Environment.NewLine,
244 " }",
245 "",
246 " public static partial class {3}TupleDefinitions",
247 " {",
248 " public static readonly Version Version = new Version(\"4.0.0\");",
249 "",
250 " public static IntermediateTupleDefinition ByName(string name)",
251 " {",
252 " if (!Enum.TryParse(name, out {3}TupleDefinitionType type))",
253 " {",
254 " return null;",
255 " }",
256 "",
257 " return ByType(type);",
258 " }",
259 "",
260 " public static IntermediateTupleDefinition ByType({3}TupleDefinitionType type)",
261 " {",
262 " switch (type)",
263 " {");
264
265 var caseFormat = String.Join(Environment.NewLine,
266 " case {3}TupleDefinitionType.{1}:",
267 " return {3}TupleDefinitions.{1};",
268 "");
269
270 var footer = String.Join(Environment.NewLine,
271 " default:",
272 " throw new ArgumentOutOfRangeException(nameof(type));",
273 " }",
274 " }",
275 " }",
276 "}");
277
278 var sb = new StringBuilder();
279
280 sb.AppendLine(header.Replace("{2}", ns).Replace("{3}", prefix));
281 foreach (var tupleName in tupleNames)
282 {
283 sb.AppendLine(namesFormat.Replace("{1}", tupleName).Replace("{2}", ns).Replace("{3}", prefix));
284 }
285 sb.AppendLine(midpoint.Replace("{2}", ns).Replace("{3}", prefix));
286 foreach (var tupleName in tupleNames)
287 {
288 sb.AppendLine(caseFormat.Replace("{1}", tupleName).Replace("{2}", ns).Replace("{3}", prefix));
289 }
290 sb.AppendLine(footer);
291
292 return sb.ToString();
293 }
294
295 private static string ConvertToFieldType(string fieldType)
296 {
297 switch (fieldType.ToLowerInvariant())
298 {
299 case "bool":
300 return "Bool";
301
302 case "string":
303 case "preserved":
304 return "String";
305
306 case "number":
307 return "Number";
308
309 case "path":
310 return "Path";
311 }
312
313 throw new ArgumentException(fieldType);
314 }
315
316 private static string ConvertToClrType(string fieldType)
317 {
318 switch (fieldType.ToLowerInvariant())
319 {
320 case "bool":
321 return "bool";
322
323 case "string":
324 case "preserved":
325 return "string";
326
327 case "number":
328 return "int";
329
330 case "path":
331 return "string";
332 }
333
334 throw new ArgumentException(fieldType);
335 }
336
337 private static int CompareTupleDefinitions(object x, object y)
338 {
339 var first = (JsonObject)x;
340 var second = (JsonObject)y;
341
342 var firstType = first.Keys.Single();
343 var secondType = second.Keys.Single();
344
345 return firstType.CompareTo(secondType);
346 }
347 }
348}