-
Notifications
You must be signed in to change notification settings - Fork 200
Support for json arrays + some rewrite #186
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,113 @@ | ||
| // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. | ||
| // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
|
||
| using System; | ||
| using System.Collections.Generic; | ||
| using System.IO; | ||
| using System.Linq; | ||
| using Newtonsoft.Json; | ||
| using Newtonsoft.Json.Linq; | ||
|
|
||
| namespace Microsoft.Framework.ConfigurationModel.Json | ||
| { | ||
| internal class JsonConfigurationFileParser | ||
| { | ||
| private readonly IDictionary<string, string> _data = new SortedDictionary<string, string>(StringComparer.OrdinalIgnoreCase); | ||
| private readonly Stack<string> _context = new Stack<string>(); | ||
| private string _currentPath; | ||
|
|
||
| private JsonTextReader _reader; | ||
|
|
||
| public IDictionary<string, string> Parse(Stream input) | ||
| { | ||
| _data.Clear(); | ||
| _reader = new JsonTextReader(new StreamReader(input)); | ||
| _reader.DateParseHandling = DateParseHandling.None; | ||
|
|
||
| var jsonConfig = JObject.Load(_reader); | ||
|
|
||
| VisitJObject(jsonConfig); | ||
|
|
||
| return _data; | ||
| } | ||
|
|
||
| private void VisitJObject(JObject jObject) | ||
| { | ||
| foreach (var property in jObject.Properties()) | ||
| { | ||
| EnterContext(property.Name); | ||
| VisitProperty(property); | ||
| ExitContext(); | ||
| } | ||
| } | ||
|
|
||
| private void VisitProperty(JProperty property) | ||
| { | ||
| VisitToken(property.Value); | ||
| } | ||
|
|
||
| private void VisitToken(JToken token) | ||
| { | ||
| switch (token.Type) | ||
| { | ||
| case JTokenType.Object: | ||
| VisitJObject(token.Value<JObject>()); | ||
| break; | ||
|
|
||
| case JTokenType.Array: | ||
| VisitArray(token.Value<JArray>()); | ||
| break; | ||
|
|
||
| case JTokenType.Integer: | ||
| case JTokenType.Float: | ||
| case JTokenType.String: | ||
| case JTokenType.Boolean: | ||
| case JTokenType.Bytes: | ||
| case JTokenType.Raw: | ||
| case JTokenType.Null: | ||
| VisitPrimitive(token); | ||
| break; | ||
|
|
||
| default: | ||
| throw new FormatException(Resources.FormatError_UnsupportedJSONToken( | ||
| _reader.TokenType, | ||
| _reader.Path, | ||
| _reader.LineNumber, | ||
| _reader.LinePosition)); | ||
| } | ||
| } | ||
|
|
||
| private void VisitArray(JArray array) | ||
| { | ||
| for (int index = 0; index < array.Count; index++) | ||
| { | ||
| EnterContext(index.ToString()); | ||
| VisitToken(array[index]); | ||
| ExitContext(); | ||
| } | ||
| } | ||
|
|
||
| private void VisitPrimitive(JToken data) | ||
| { | ||
| var key = _currentPath; | ||
|
|
||
| if (_data.ContainsKey(key)) | ||
| { | ||
| throw new FormatException(Resources.FormatError_KeyIsDuplicated(key)); | ||
| } | ||
| _data[key] = data.ToString(); | ||
| } | ||
|
|
||
| private void EnterContext(string context) | ||
| { | ||
| _context.Push(context); | ||
| _currentPath = string.Join(":", _context.Reverse()); | ||
| } | ||
|
|
||
| private void ExitContext() | ||
| { | ||
| _context.Pop(); | ||
| _currentPath = string.Join(":", _context.Reverse()); | ||
| } | ||
| } | ||
| } | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -9,6 +9,10 @@ | |
| "frameworks": { | ||
| "net45": { }, | ||
| "dnx451": { }, | ||
| "dnxcore50": { } | ||
| "dnxcore50": { | ||
| "dependencies": { | ||
| "System.Dynamic.Runtime": "4.0.10-*" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why's this needed?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, json.net requires it
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Or, I should clarify: when I use a particular type from json.net, the compiler complains about that missing reference
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Bug in Json.NET's nuspec?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we need to file a bug on this for Json.NET? And a bug for us to track removing this? This doesn't seem right.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will investigate this to see if it is an actual bug
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks! |
||
| } | ||
| } | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. | ||
| // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
|
||
| using System; | ||
| using System.Collections.Generic; | ||
|
|
||
| namespace Microsoft.Framework.ConfigurationModel | ||
| { | ||
| public class ConfigurationKeyComparer : IComparer<string> | ||
| { | ||
| private const char Separator = ':'; | ||
|
|
||
| public static ConfigurationKeyComparer Instance { get; } = new ConfigurationKeyComparer(); | ||
|
|
||
| public int Compare(string x, string y) | ||
| { | ||
| var xParts = x?.Split(Separator) ?? new string[0]; | ||
| var yParts = y?.Split(Separator) ?? new string[0]; | ||
|
|
||
| // Compare each part until we get two parts that are not equal | ||
| for (int i = 0; i < Math.Min(xParts.Length, yParts.Length); i++) | ||
| { | ||
| x = xParts[i]; | ||
| y = yParts[i]; | ||
|
|
||
| var value1 = 0; | ||
| var value2 = 0; | ||
|
|
||
| var xIsInt = x != null && int.TryParse(x, out value1); | ||
| var yIsInt = y != null && int.TryParse(y, out value2); | ||
|
|
||
| int result = 0; | ||
|
|
||
| if (!xIsInt && !yIsInt) | ||
| { | ||
| // Both are strings | ||
| result = string.Compare(x, y, StringComparison.OrdinalIgnoreCase); | ||
| } | ||
| else if (xIsInt && yIsInt) | ||
| { | ||
| // Both are int | ||
| result = value1 - value2; | ||
| } | ||
| else | ||
| { | ||
| // Only one of them is int | ||
| result = xIsInt ? -1 : 1; | ||
| } | ||
|
|
||
| if (result != 0) | ||
| { | ||
| // One of them is different | ||
| return result; | ||
| } | ||
| } | ||
|
|
||
| // If we get here, the common parts are equal. | ||
| // If they are of the same length, then they are totally identical | ||
| return xParts.Length - yParts.Length; | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -39,5 +39,6 @@ | |
| [assembly: AssemblyVersion("1.0.0.0")] | ||
| [assembly: AssemblyFileVersion("1.0.0.0")] | ||
| [assembly: InternalsVisibleTo("Microsoft.Framework.ConfigurationModel.Test")] | ||
| [assembly: InternalsVisibleTo("Microsoft.Framework.ConfigurationModel.Json.Test")] | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. IVT is to be used only for the unit test assembly of this assembly. Make the type(s) in question public and move to a
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See the PR that fixes this: #188 |
||
| [assembly: NeutralResourcesLanguage("en-US")] | ||
| [assembly: AssemblyMetadata("Serviceable", "True")] | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this syntax. Much more clear than my previous approach 👍