diff options
Diffstat (limited to 'src/TablesAndTuples/Program.cs')
-rw-r--r-- | src/TablesAndTuples/Program.cs | 348 |
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 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.IO; | ||
4 | using System.Linq; | ||
5 | using System.Text; | ||
6 | using System.Xml.Linq; | ||
7 | using SimpleJson; | ||
8 | |||
9 | namespace 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 | } | ||