diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/WikiExample.Source.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/WikiExample.Source.json new file mode 100644 index 0000000..555f1ce --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/WikiExample.Source.json @@ -0,0 +1,8 @@ +{ + "Version": 1, + "Settings": { + "Setting01": "Default01", + "Setting02": "Default02" + }, + "SupportedVersions": [ 1, 2, 3 ] +} \ No newline at end of file diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/WikiExample.Test.Expected.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/WikiExample.Test.Expected.json new file mode 100644 index 0000000..ba4defe --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/WikiExample.Test.Expected.json @@ -0,0 +1,16 @@ +{ + // Overriden by the transformation file + "Version": 2, + "Settings": { + // Overriden by the transformation file + "Setting01": "NewValue01", + // Not present in the transformation file, unchanged + "Setting02": "Default02", + // Added by the transformation file + "Setting03": "NewValue03" + }, + // The array in the transformation file was appended + "SupportedVersions": [ 1, 2, 3, 4, 5 ], + // Added by the transformation file + "UseThis": true +} \ No newline at end of file diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/WikiExample.Test.Transform.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/WikiExample.Test.Transform.json new file mode 100644 index 0000000..fcc9c08 --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/WikiExample.Test.Transform.json @@ -0,0 +1,9 @@ +{ + "Version": 2, + "Settings": { + "Setting01": "NewValue01", + "Setting03": "NewValue03" + }, + "SupportedVersions": [ 4, 5 ], + "UseThis": true +} \ No newline at end of file diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.MissingPath.Expected.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.MissingPath.Expected.json new file mode 100644 index 0000000..a4ef408 --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.MissingPath.Expected.json @@ -0,0 +1,18 @@ +{ + "A": {}, + "B": { + "B1": 1, + "B2": 2 + }, + "C": { + "C1": { + "C11": true + }, + "C2": 2 + }, + "D": 4, + "E": [ + { "E1": 5 }, + { "E2": 6 } + ] +} diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.MissingPath.Transform.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.MissingPath.Transform.json new file mode 100644 index 0000000..e918116 --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.MissingPath.Transform.json @@ -0,0 +1,15 @@ +{ + "D": { + "@jdt.merge": 4 + }, + "E": [ + { + "E1": { + "@jdt.merge": 5 + } + }, + { + "E2@jdt.merge": 6 + } + ] +} diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/WikiExample.Source.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/WikiExample.Source.json new file mode 100644 index 0000000..d2eab53 --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/WikiExample.Source.json @@ -0,0 +1,27 @@ +{ + "A": { + "TransformThis": true + }, + "B": { + "TransformThis": false + }, + "C": { + }, + "D": { + "TransformThis": "WrongValue" + }, + "E": { + "TransformThis": false, + "Items": [ + { + "Value": 10 + }, + { + "Value": 20 + }, + { + "Value": 30 + } + ] + } +} \ No newline at end of file diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/WikiExample.Test.Expected.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/WikiExample.Test.Expected.json new file mode 100644 index 0000000..10feb74 --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/WikiExample.Test.Expected.json @@ -0,0 +1,34 @@ +{ + "A": { + "TransformThis": true, + "Default": 0, + "Transformed": true + }, + "B": { + "TransformThis": false, + "Default": 0 + }, + "C": { + "Default": 0 + }, + "D": { + "TransformThis": "WrongValue", + "Default": 0 + }, + "E": { + "TransformThis": false, + "Items": [ + { + "Value": 15, + "Changed": true + }, + { + "Value": 20 + }, + { + "Value": 30 + } + ], + "Default": 0 + } +} \ No newline at end of file diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/WikiExample.Test.Transform.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/WikiExample.Test.Transform.json new file mode 100644 index 0000000..5aae52e --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/WikiExample.Test.Transform.json @@ -0,0 +1,28 @@ +{ + //Executes for all nodes on this level + "@jdt.merge": [ + { + "@jdt.path": "*", + "@jdt.value": { + "Default": 0 + } + }, + //This only executes for matching nodes + { + "@jdt.path": "A", + "@jdt.value": { + "Transformed": true + } + } + ], + "E": { + // Accessing objects in array + "@jdt.merge": { + "@jdt.path": "Items[?(@.Value < 15)]", + "@jdt.value": { + "Value": 15, + "Changed": true + } + } + } +} \ No newline at end of file diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/SimpleArray.RemoveWhole.Expected.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/SimpleArray.RemoveWhole.Expected.json new file mode 100644 index 0000000..c142242 --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/SimpleArray.RemoveWhole.Expected.json @@ -0,0 +1,10 @@ +{ + "A": null, + "B": [ + "b-one", + "b-two", + "b-three", + "b-four", + "b-five" + ] +} diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/SimpleArray.RemoveWhole.Transform.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/SimpleArray.RemoveWhole.Transform.json new file mode 100644 index 0000000..5c7d3cd --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/SimpleArray.RemoveWhole.Transform.json @@ -0,0 +1,5 @@ +{ + "A": { + "@jdt.remove": true + } +} diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/SimpleArray.Source.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/SimpleArray.Source.json new file mode 100644 index 0000000..c0f5bd1 --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/SimpleArray.Source.json @@ -0,0 +1,14 @@ +{ + "A": [ + "a-one", + "a-two", + "a-three" + ], + "B": [ + "b-one", + "b-two", + "b-three", + "b-four", + "b-five" + ] +} diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/WikiExample.Source.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/WikiExample.Source.json new file mode 100644 index 0000000..c918ff0 --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/WikiExample.Source.json @@ -0,0 +1,14 @@ +{ + "A": 1, + "Astar": 10, + "B": 2, + "C": { + "C1": 31, + "C2": 32 + }, + "D": { + "D1": 41, + "D2": 42, + "D3": 43 + } +} \ No newline at end of file diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/WikiExample.Test.Expected.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/WikiExample.Test.Expected.json new file mode 100644 index 0000000..c428c42 --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/WikiExample.Test.Expected.json @@ -0,0 +1,11 @@ +{ + // Astar is completely removed + "A": 1, + "B": 2, + // All nodes are removed + "C": null, + "D": { + "D1": 41 + // Multiple nodes were removed + } +} \ No newline at end of file diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/WikiExample.Test.Transform.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/WikiExample.Test.Transform.json new file mode 100644 index 0000000..18e11a7 --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/WikiExample.Test.Transform.json @@ -0,0 +1,9 @@ +{ + "@jdt.remove": "Astar", + "C": { + "@jdt.remove": true + }, + "D": { + "@jdt.remove": [ "D2", "D3" ] + } +} \ No newline at end of file diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/WikiExample2.Source.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/WikiExample2.Source.json new file mode 100644 index 0000000..728cc4e --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/WikiExample2.Source.json @@ -0,0 +1,14 @@ +{ + "A": { + "RemoveThis": true + }, + "B": { + "RemoveThis": false + }, + "C": { + "C1": 1, + "C2": { + "C21": 21 + } + } +} \ No newline at end of file diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/WikiExample2.Test.Expected.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/WikiExample2.Test.Expected.json new file mode 100644 index 0000000..3c62d5b --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/WikiExample2.Test.Expected.json @@ -0,0 +1,10 @@ +{ + "B": { + "RemoveThis": false + }, + "C": { + "C1": 1, + "C2": { + } + } +} \ No newline at end of file diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/WikiExample2.Test.Transform.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/WikiExample2.Test.Transform.json new file mode 100644 index 0000000..df80552 --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/WikiExample2.Test.Transform.json @@ -0,0 +1,12 @@ +{ + //Remove only matching nodes from this level + "@jdt.remove": { + "@jdt.path": "A" + }, + "C": { + //Specify a relative path to the node + "@jdt.remove": { + "@jdt.path": "C2.C21" + } + } +} \ No newline at end of file diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.MissingPath.Expected.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.MissingPath.Expected.json new file mode 100644 index 0000000..4944400 --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.MissingPath.Expected.json @@ -0,0 +1,15 @@ +{ + "A": [ + { "Index": 1 }, + { "Index": 2 }, + { "Index": 3 } + ], + "B": [ + { "Rename": true, "ToChange": 1 }, + { "Rename": false, "ToChange": 1 }, + { "Rename": "WrongValue", "ToChange": 1 }, + { "HasRename": false, "ToChange": 1 }, + { "Rename": true, "ToChange": 1 } + ], + "C": {} +} diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.MissingPath.Transform.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.MissingPath.Transform.json new file mode 100644 index 0000000..6547ef4 --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.MissingPath.Transform.json @@ -0,0 +1,8 @@ +{ + "C": { + "@jdt.rename": { + "@jdt.path": "Item", + "@jdt.value": "Changed" + } + } +} diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.ScriptPath.Expected.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.ScriptPath.Expected.json index c0d2dce..f3a5019 100644 --- a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.ScriptPath.Expected.json +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.ScriptPath.Expected.json @@ -6,9 +6,9 @@ ], "B": [ { "Rename": true, "Changed": 1 }, - { "Rename": false, "ToChange": 2 }, - { "Rename": "WrongValue", "ToChange": 3 }, - { "HasRename": false, "ToChange": 4 }, - { "Rename": true, "Changed": 5 } + { "Rename": false, "ToChange": 1 }, + { "Rename": "WrongValue", "ToChange": 1 }, + { "HasRename": false, "ToChange": 1 }, + { "Rename": true, "Changed": 1 } ] } diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.ScriptPath.Transform .json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.ScriptPath.Transform.json similarity index 51% rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.ScriptPath.Transform .json rename to src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.ScriptPath.Transform.json index 54a91db..200a595 100644 --- a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.ScriptPath.Transform .json +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.ScriptPath.Transform.json @@ -1,6 +1,6 @@ { "@jdt.rename": { - "@jdt.path": "$.B[?(@.Rename == true)].ToChange", + "@jdt.path": "B[?(@.Rename == true)].ToChange", "@jdt.value": "Changed" } } diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/WikiExample.Source.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/WikiExample.Source.json new file mode 100644 index 0000000..404f0cb --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/WikiExample.Source.json @@ -0,0 +1,14 @@ +{ + "A": { + "A1": 11, + "A2": { + "A21": 121, + "A22": 122 + } + }, + "B": [ + 21, + 22 + ], + "C": 3 +} \ No newline at end of file diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/WikiExample.Test.Expected.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/WikiExample.Test.Expected.json new file mode 100644 index 0000000..d600ac2 --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/WikiExample.Test.Expected.json @@ -0,0 +1,17 @@ +{ + // Does not alter result + "Astar": { + "A1": 11, + "A2": { + "A21": 121, + "A22": 122 + } + }, + // Does not depend on object type + "Bstar": [ + 21, + 22 + ], + // Does not alter siblings + "C": 3 +} \ No newline at end of file diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/WikiExample.Test.Transform.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/WikiExample.Test.Transform.json new file mode 100644 index 0000000..7191ff7 --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/WikiExample.Test.Transform.json @@ -0,0 +1,6 @@ +{ + "@jdt.rename": { + "A": "Astar", + "B": "Bstar" + } +} \ No newline at end of file diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/WikiExample2.Source.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/WikiExample2.Source.json new file mode 100644 index 0000000..d4a6ef7 --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/WikiExample2.Source.json @@ -0,0 +1,18 @@ +{ + "A": { + "RenameThis": true + }, + "B": { + "RenameThis": false + }, + "C": [ + { + "Name": "C01", + "Value": 1 + }, + { + "Name": "C02", + "Value": 2 + } + ] +} \ No newline at end of file diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/WikiExample2.Test.Expected.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/WikiExample2.Test.Expected.json new file mode 100644 index 0000000..3654a3f --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/WikiExample2.Test.Expected.json @@ -0,0 +1,21 @@ +{ + // Only this node matches the path + "Astar": { + "RenameThis": true + }, + "B": { + "RenameThis": false + }, + // Renaming nodes from an object + // in the array is allowed + "C": [ + { + "Nstar": "C01", + "Value": 1 + }, + { + "Nstar": "C02", + "Value": 2 + } + ] +} \ No newline at end of file diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/WikiExample2.Test.Transform.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/WikiExample2.Test.Transform.json new file mode 100644 index 0000000..b881fb1 --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/WikiExample2.Test.Transform.json @@ -0,0 +1,12 @@ +{ + "@jdt.rename": { + "@jdt.path": "A", + "@jdt.value": "Astar" + }, + "C": { + "@jdt.rename": { + "@jdt.path": "[*].Name", + "@jdt.value": "Nstar" + } + } +} \ No newline at end of file diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.MissingPath.Expected.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.MissingPath.Expected.json new file mode 100644 index 0000000..4207bbe --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.MissingPath.Expected.json @@ -0,0 +1,32 @@ +{ + "A": [ + { "Index": 1 }, + { "Index": 2 }, + { "Index": 3 } + ], + "B": [ + { "Replace": true }, + { "Replace": false }, + { "Replace": "WrongValue" }, + { "HasReplace": true }, + { "Replace": true } + ], + "C": [ + 1, + 2 + ], + "D": [ + 3, + 4 + ], + "E": { + "E1": [ + 5, + 6 + ], + "E2": [ + 7, + 8 + ] + } +} diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.MissingPath.Transform.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.MissingPath.Transform.json new file mode 100644 index 0000000..58edf06 --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.MissingPath.Transform.json @@ -0,0 +1,28 @@ +{ + "C": { + "@jdt.replace": [ + [ + 1, + 2 + ] + ] + }, + "D@jdt.replace": [ + 3, + 4 + ], + "E": { + "E1": { + "@jdt.replace": [ + [ + 5, + 6 + ] + ] + }, + "E2@jdt.replace": [ + 7, + 8 + ] + } +} diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/SimpleArray.Source.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/SimpleArray.Source.json new file mode 100644 index 0000000..04bd771 --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/SimpleArray.Source.json @@ -0,0 +1,14 @@ +{ + "A": [ + 1, + 2, + 3 + ], + "B": [ + "string1", + "string2", + "string3", + "string4", + "string5" + ] +} diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/SimpleArray.WithArray.Expected.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/SimpleArray.WithArray.Expected.json new file mode 100644 index 0000000..d621b17 --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/SimpleArray.WithArray.Expected.json @@ -0,0 +1,13 @@ +{ + "A": [ + 4, + 5 + ], + "B": [ + "string1", + "string2", + "string3", + "string4", + "string5" + ] +} diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/SimpleArray.WithArray.Transform.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/SimpleArray.WithArray.Transform.json new file mode 100644 index 0000000..a8d2273 --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/SimpleArray.WithArray.Transform.json @@ -0,0 +1,10 @@ +{ + "A": { + "@jdt.replace": [ + [ + 4, + 5 + ] + ] + } +} diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/WikiExample.Source.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/WikiExample.Source.json new file mode 100644 index 0000000..d4c5996 --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/WikiExample.Source.json @@ -0,0 +1,13 @@ +{ + "A": { + "A1": "11" + }, + "B": { + "1B": 12, + "2B": 22 + }, + "C": { + "C1": 31, + "C2": 32 + } +} \ No newline at end of file diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/WikiExample.Test.Expected.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/WikiExample.Test.Expected.json new file mode 100644 index 0000000..0e12376 --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/WikiExample.Test.Expected.json @@ -0,0 +1,15 @@ +{ + "A": 1, + "B": { + "B1": 11, + "B2": 12 + }, + "C": [ + { + "Value": 31 + }, + { + "Value": 32 + } + ] +} \ No newline at end of file diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/WikiExample.Test.Transform.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/WikiExample.Test.Transform.json new file mode 100644 index 0000000..fea08d6 --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/WikiExample.Test.Transform.json @@ -0,0 +1,25 @@ +{ + "A": { + "@jdt.replace": 1 + }, + "B": { + "@jdt.replace": { + "B1": 11, + "B2": 12 + } + }, + "C": { + // Double brackets are needed to specify + // the array as the transformation value + "@jdt.replace": [ + [ + { + "Value": 31 + }, + { + "Value": 32 + } + ] + ] + } +} \ No newline at end of file diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/WikiExample2.Source.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/WikiExample2.Source.json new file mode 100644 index 0000000..e6dd481 --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/WikiExample2.Source.json @@ -0,0 +1,14 @@ +{ + "A": { + "A1": 11, + "A2": "Replace" + }, + "B": [ + { + "ReplaceThis": true + }, + { + "ReplaceThis": false + } + ] +} \ No newline at end of file diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/WikiExample2.Test.Expected.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/WikiExample2.Test.Expected.json new file mode 100644 index 0000000..349903c --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/WikiExample2.Test.Expected.json @@ -0,0 +1,15 @@ +{ + "A": { + "A1": 11, + "A2": 12 + }, + "B": [ + { + // The entire object was replaced + "Replaced": true + }, + { + "ReplaceThis": false + } + ] +} \ No newline at end of file diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/WikiExample2.Test.Transform.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/WikiExample2.Test.Transform.json new file mode 100644 index 0000000..4cbe52e --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/WikiExample2.Test.Transform.json @@ -0,0 +1,14 @@ +{ + "@jdt.replace": { + "@jdt.path": "$.A.A2", + "@jdt.value": 12 + }, + "B": { + "@jdt.replace": { + "@jdt.path": "[?(@.ReplaceThis == true)]", + "@jdt.value": { + "Replaced": true + } + } + } +} \ No newline at end of file diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Microsoft.VisualStudio.Jdt.Tests.csproj b/src/Microsoft.VisualStudio.Jdt.Tests/Microsoft.VisualStudio.Jdt.Tests.csproj index 666def7..37d7b81 100644 --- a/src/Microsoft.VisualStudio.Jdt.Tests/Microsoft.VisualStudio.Jdt.Tests.csproj +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Microsoft.VisualStudio.Jdt.Tests.csproj @@ -1,7 +1,7 @@  - net472;net5.0 + net472;net8.0 false $(NoWarn);CS1591 diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/TransformTest.cs b/src/Microsoft.VisualStudio.Jdt.Tests/TransformTest.cs index 317e743..cb2cbd5 100644 --- a/src/Microsoft.VisualStudio.Jdt.Tests/TransformTest.cs +++ b/src/Microsoft.VisualStudio.Jdt.Tests/TransformTest.cs @@ -178,7 +178,7 @@ private static void BaseTransformTest(string inputsDirectory, string testName) var transformed = JObject.Load(jsonReader); - Assert.True(JObject.DeepEquals(expected, transformed)); + Assert.True(JObject.DeepEquals(expected, transformed), $"expected: {expected}\ntransformed: {transformed}"); } } } diff --git a/src/Microsoft.VisualStudio.Jdt/JdtDefaultTransform.cs b/src/Microsoft.VisualStudio.Jdt/JdtDefaultTransform.cs new file mode 100644 index 0000000..b9f1fe9 --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt/JdtDefaultTransform.cs @@ -0,0 +1,18 @@ +namespace Microsoft.VisualStudio.Jdt +{ + /// + /// Available default transforms for objects and arrays. + /// + public enum JdtDefaultTransform + { + /// + /// Perform merge when doing the default transform. + /// + Merge, + + /// + /// Perform replace when doing the default transform. + /// + Replace, + } +} diff --git a/src/Microsoft.VisualStudio.Jdt/JdtUtilities.cs b/src/Microsoft.VisualStudio.Jdt/JdtUtilities.cs index f0a45ad..6c49171 100644 --- a/src/Microsoft.VisualStudio.Jdt/JdtUtilities.cs +++ b/src/Microsoft.VisualStudio.Jdt/JdtUtilities.cs @@ -36,6 +36,18 @@ public static bool IsJdtSyntax(string key) return !string.IsNullOrEmpty(key) && key.StartsWith(JdtSyntaxPrefix); } + /// + /// Wheter the given key corresponds to a JDT verb using inline form (e.g.: "key@jdt.replace"). + /// + /// The JSON key to analyze. + /// True if the key corresponds to a verb. + public static bool IsJdtInlineSyntax(string key) + { + // If the key is empty of does not start with the correct prefix, + // it is not a valid verb + return !string.IsNullOrEmpty(key) && !key.StartsWith(JdtSyntaxPrefix) && key.Contains(JdtSyntaxPrefix); + } + /// /// Gets the JDT syntax in the key. /// @@ -43,11 +55,33 @@ public static bool IsJdtSyntax(string key) /// The string property. Null if the property does is not JDT syntax. public static string GetJdtSyntax(string key) { - // If the key does not start with the correct prefix, it is not a JDT verb + // If the key does not start with or caontain the correct prefix, it is not a JDT verb // If it is a JDT verb, remove the prefix return IsJdtSyntax(key) ? key.Substring(JdtSyntaxPrefix.Length) : null; } + /// + /// Gets the JDT inline syntax in the key. + /// + /// The JDT key, in the correct syntax. + /// The string property. Null if the property does is not JDT syntax. + public static string GetJdtInlineSyntax(string key) + { + // If the key does not start with or caontain the correct prefix, it is not a JDT verb + // If it is a JDT verb, remove the prefix + return IsJdtInlineSyntax(key) ? key.Substring(key.IndexOf(JdtSyntaxPrefix) + JdtSyntaxPrefix.Length) : null; + } + + /// + /// Gets the key, stripping any JDT syntax. + /// + /// The JDT key, in the correct syntax. + /// The string property. + public static string GetJdtInlineKey(string key) + { + return IsJdtInlineSyntax(key) ? key.Substring(0, key.IndexOf(JdtSyntaxPrefix)) : null; + } + /// /// Gets the depending on the Newtonsoft version /// This is due to a bug in previous versions of JSON.Net that loaded line info on ignore and vice-versa diff --git a/src/Microsoft.VisualStudio.Jdt/JsonTransformationMemoryLogger.cs b/src/Microsoft.VisualStudio.Jdt/JsonTransformationMemoryLogger.cs new file mode 100644 index 0000000..1378c37 --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt/JsonTransformationMemoryLogger.cs @@ -0,0 +1,159 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE file in the project root for full license information. + +namespace Microsoft.VisualStudio.Jdt +{ + using System; + using System.Collections.Generic; + + /// + /// Memory logger. + /// + public class JsonTransformationMemoryLogger : IJsonTransformationLogger + { + /// + /// Gets the error log. + /// + public List ErrorLog { get; } = new List(); + + /// + /// Gets the warning log. + /// + public List WarningLog { get; } = new List(); + + /// + /// Gets the message log. + /// + public List MessageLog { get; } = new List(); + + /// + public void LogError(string message) + { + this.ErrorLog.Add(new LogEntry() + { + Message = message, + }); + } + + /// + public void LogError(string message, string fileName, int lineNumber, int linePosition) + { + this.ErrorLog.Add(new LogEntry() + { + Message = message, + FileName = fileName, + LineNumber = lineNumber, + LinePosition = linePosition, + }); + } + + /// + public void LogErrorFromException(Exception ex) + { + this.ErrorLog.Add(new LogEntry() + { + Exception = ex, + Message = ex.Message, + }); + } + + /// + public void LogErrorFromException(Exception ex, string fileName, int lineNumber, int linePosition) + { + this.ErrorLog.Add(new LogEntry() + { + Exception = ex, + Message = ex.Message, + FileName = fileName, + LineNumber = lineNumber, + LinePosition = linePosition, + }); + } + + /// + public void LogMessage(string message) + { + this.MessageLog.Add(new LogEntry() + { + Message = message, + }); + } + + /// + public void LogMessage(string message, string fileName, int lineNumber, int linePosition) + { + this.MessageLog.Add(new LogEntry() + { + Message = message, + FileName = fileName, + LineNumber = lineNumber, + LinePosition = linePosition, + }); + } + + /// + public void LogWarning(string message) + { + this.WarningLog.Add(new LogEntry() + { + Message = message, + }); + } + + /// + public void LogWarning(string message, string fileName) + { + this.WarningLog.Add(new LogEntry() + { + Message = message, + FileName = fileName, + LineNumber = 0, + LinePosition = 0, + }); + } + + /// + public void LogWarning(string message, string fileName, int lineNumber, int linePosition) + { + this.WarningLog.Add(new LogEntry() + { + Message = message, + FileName = fileName, + LineNumber = lineNumber, + LinePosition = linePosition, + }); + } + + /// + /// A simple entry for the logger. + /// Corresponds to an error, warning or message. + /// + public struct LogEntry + { + /// + /// Gets or sets the log exception. + /// + public Exception Exception { get; set; } + + /// + /// Gets or sets the log message. + /// + public string Message { get; set; } + + /// + /// Gets or sets the file that caused the entry. + /// + public string FileName { get; set; } + + /// + /// Gets or sets the line in the file. + /// + public int LineNumber { get; set; } + + /// + /// Gets or sets the position in the line. + /// + public int LinePosition { get; set; } + } + } +} diff --git a/src/Microsoft.VisualStudio.Jdt/Processors/JdtArrayProcessor.cs b/src/Microsoft.VisualStudio.Jdt/Processors/JdtArrayProcessor.cs index 7561be8..06dba84 100644 --- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtArrayProcessor.cs +++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtArrayProcessor.cs @@ -12,7 +12,7 @@ namespace Microsoft.VisualStudio.Jdt internal abstract class JdtArrayProcessor : JdtProcessor { /// - internal override void Process(JObject source, JObject transform, JsonTransformationContextLogger logger) + internal override void Process(JToken source, JObject transform, JsonTransformationContextLogger logger) { if (source == null) { @@ -45,7 +45,7 @@ internal override void Process(JObject source, JObject transform, JsonTransforma /// Value of the transform. /// The transformation context logger. /// True if transforms should continue. - protected abstract bool ProcessCore(JObject source, JToken transformValue, JsonTransformationContextLogger logger); + protected abstract bool ProcessCore(JToken source, JToken transformValue, JsonTransformationContextLogger logger); /// /// Performs the initial logic of processing arrays. @@ -55,7 +55,7 @@ internal override void Process(JObject source, JObject transform, JsonTransforma /// Value of the transform. /// The transformation context logger. /// True if transforms should continue. - private bool Transform(JObject source, JToken transformValue, JsonTransformationContextLogger logger) + private bool Transform(JToken source, JToken transformValue, JsonTransformationContextLogger logger) { if (transformValue.Type == JTokenType.Array) { diff --git a/src/Microsoft.VisualStudio.Jdt/Processors/JdtDefault.cs b/src/Microsoft.VisualStudio.Jdt/Processors/JdtDefault.cs index 4da52d4..3434a48 100644 --- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtDefault.cs +++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtDefault.cs @@ -5,6 +5,7 @@ namespace Microsoft.VisualStudio.Jdt { using System; using System.Linq; + using System.Xml.Linq; using Newtonsoft.Json.Linq; /// @@ -12,11 +13,16 @@ namespace Microsoft.VisualStudio.Jdt /// internal class JdtDefault : JdtProcessor { + private JdtDefaultTransform defaultTransform = JdtDefaultTransform.Merge; + /// public override string Verb { get; } = null; /// - internal override void Process(JObject source, JObject transform, JsonTransformationContextLogger logger) + public override bool Expandable { get; } = false; + + /// + internal override void Process(JToken source, JObject transform, JsonTransformationContextLogger logger) { if (source == null) { @@ -28,35 +34,110 @@ internal override void Process(JObject source, JObject transform, JsonTransforma throw new ArgumentNullException(nameof(transform)); } - // JDT Verbs are not handled here - foreach (JProperty transformNode in transform.Properties() + if (source.Type == JTokenType.Object) + { + // JDT Verbs are not handled here + foreach (JProperty transformNode in transform.Properties() .Where(p => !JdtUtilities.IsJdtSyntax(p.Name))) + { + JToken nodeToTransform; + if (((JObject)source).TryGetValue(transformNode.Name, out nodeToTransform)) + { + // If the node is present in both transform and source, analyze the types + // If both are objects, that is a recursive transformation, not handled here + if (nodeToTransform.Type == JTokenType.Array && transformNode.Value.Type == JTokenType.Array) + { + // If the original and transform are arrays, merge or replace the contents, depending on current mode + if (this.defaultTransform == JdtDefaultTransform.Merge) + { + ((JArray)nodeToTransform).Merge(transformNode.Value.DeepClone()); + } + else + { + ((JArray)nodeToTransform).Replace(transformNode.Value.DeepClone()); + } + } + else if (nodeToTransform.Type != JTokenType.Object || transformNode.Value.Type != JTokenType.Object) + { + // For non-arrays and non-objects, just replace them + source[transformNode.Name] = transformNode.Value.DeepClone(); + } + } + else + { + var shouldResetMode = this.defaultTransform == JdtDefaultTransform.Merge; + if (shouldResetMode) + { + // While doing default transformation on an object, switch to replace by default + // This works as expected as long as a single level of JDT Verbs is used (more are unsupported anyway) + this.defaultTransform = JdtDefaultTransform.Replace; + } + + // If the tranform node is an object, cleaning it and transforming it on itself resolves all remaining JDT Verbs + // Otherwise JDT Verbs would polute the source object + this.ProcessTransformAndCleanJdtProperties(transformNode.Value, logger); + + if (shouldResetMode) + { + this.defaultTransform = JdtDefaultTransform.Merge; + } + + // If the node is not present in the original, add it + ((JObject)source).Add(transformNode.DeepClone()); + } + } + } + else if (!transform.Properties().Where(p => JdtUtilities.IsJdtSyntax(p.Name)).Any()) { - JToken nodeToTransform; - if (source.TryGetValue(transformNode.Name, out nodeToTransform)) + source.Replace(transform.DeepClone()); + } + + this.Successor.Process(source, transform, logger); + } + + /// + /// Cleans JDT Value properties and processes itself as a transform. + /// + /// JObject or JArray. + /// Logger. + /// The same reference. + private JToken ProcessTransformAndCleanJdtProperties(JToken token, JsonTransformationContextLogger logger) + { + if (token.Type == JTokenType.Array) + { + foreach (var item in ((JArray)token).Children()) { - // If the node is present in both transform and source, analyze the types - // If both are objects, that is a recursive transformation, not handled here - if (nodeToTransform.Type == JTokenType.Array && transformNode.Value.Type == JTokenType.Array) + this.ProcessTransformAndCleanJdtProperties(item, logger); + } + } + else if (token.Type == JTokenType.Object) + { + var jObject = (JObject)token; + var selfTransform = (JObject)jObject.DeepClone(); + foreach (JProperty node in jObject.Properties().ToArray()) + { + if (JdtUtilities.IsJdtSyntax(node.Name)) { - // If the original and transform are arrays, merge the contents together - ((JArray)nodeToTransform).Merge(transformNode.Value.DeepClone()); + // Rename any JDT verb nodes + jObject.Remove(node.Name); } - else if (nodeToTransform.Type != JTokenType.Object || transformNode.Value.Type != JTokenType.Object) + else if (JdtUtilities.IsJdtInlineSyntax(node.Name)) { - // TO DO: Verify if object has JDT verbs. They shouldn't be allowed here because they won't be processed - // If the contents are different, execute the replace - source[transformNode.Name] = transformNode.Value.DeepClone(); + // Rename any JDT inline verb nodes and replace them with empty JObjects + // As JDT inline verbs are supported in merge or replace, this is sufficient + node.Replace(new JProperty(JdtUtilities.GetJdtInlineKey(node.Name), new JObject())); } } - else + + ProcessTransform(token, selfTransform, logger); + + foreach (JProperty node in jObject.Properties().ToArray()) { - // If the node is not present in the original, add it - source.Add(transformNode.DeepClone()); + this.ProcessTransformAndCleanJdtProperties(node.Value, logger); } } - this.Successor.Process(source, transform, logger); + return token; } } } diff --git a/src/Microsoft.VisualStudio.Jdt/Processors/JdtExpander.cs b/src/Microsoft.VisualStudio.Jdt/Processors/JdtExpander.cs new file mode 100644 index 0000000..2d4f7ac --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtExpander.cs @@ -0,0 +1,64 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See LICENSE file in the project root for full license information. + +namespace Microsoft.VisualStudio.Jdt +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Xml.Linq; + using Newtonsoft.Json.Linq; + + /// + /// Expands the simplified inline JDT verbs in the transformation. + /// + internal class JdtExpander : JdtProcessor + { + /// + /// Gets set of the valid verbs for the transformation. + /// + public HashSet ValidVerbs { get; } = new HashSet(); + + /// + public override string Verb { get; } = null; + + /// + public override bool Expandable { get; } = false; + + /// + internal override void Process(JToken source, JObject transform, JsonTransformationContextLogger logger) + { + if (source == null) + { + throw new ArgumentNullException(nameof(source)); + } + + if (transform == null) + { + throw new ArgumentNullException(nameof(transform)); + } + + foreach (JProperty transformNode in transform.Properties() + .Where(p => JdtUtilities.IsJdtInlineSyntax(p.Name)).ToList()) + { + string verb = JdtUtilities.GetJdtInlineSyntax(transformNode.Name); + if (verb != null) + { + if (!this.ValidVerbs.Contains(verb)) + { + throw JdtException.FromLineInfo(string.Format(Resources.ErrorMessage_InvalidInlineVerb, verb), ErrorLocation.Transform, transformNode); + } + + var newValue = new JObject( + new JProperty( + JdtUtilities.JdtSyntaxPrefix + verb, + new JArray(transformNode.Value))); + + transformNode.Replace(new JProperty(JdtUtilities.GetJdtInlineKey(transformNode.Name), newValue)); + } + } + + this.Successor.Process(source, transform, logger); + } + } +} diff --git a/src/Microsoft.VisualStudio.Jdt/Processors/JdtMerge.cs b/src/Microsoft.VisualStudio.Jdt/Processors/JdtMerge.cs index 3a9d1d2..1af72f2 100644 --- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtMerge.cs +++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtMerge.cs @@ -26,13 +26,16 @@ public JdtMerge() public override string Verb { get; } = "merge"; /// - protected override bool ProcessCore(JObject source, JToken transformValue, JsonTransformationContextLogger logger) + public override bool Expandable { get; } = true; + + /// + protected override bool ProcessCore(JToken source, JToken transformValue, JsonTransformationContextLogger logger) { - if (transformValue.Type == JTokenType.Object) + if (source.Type == JTokenType.Object && transformValue.Type == JTokenType.Object) { // If both source and transform are objects, // analyze the contents and perform the appropriate transforms - this.MergeWithObject(source, (JObject)transformValue, logger); + this.MergeWithObject((JObject)source, (JObject)transformValue, logger); } else { diff --git a/src/Microsoft.VisualStudio.Jdt/Processors/JdtProcessor.ProcessorChain.cs b/src/Microsoft.VisualStudio.Jdt/Processors/JdtProcessor.ProcessorChain.cs index 556d9c5..48225aa 100644 --- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtProcessor.ProcessorChain.cs +++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtProcessor.ProcessorChain.cs @@ -30,10 +30,14 @@ private class JdtProcessorChain public JdtProcessorChain() { + var expander = new JdtExpander(); var validator = new JdtValidator(); - // The first step of a transformation is validating the verbs - this.processors.Insert(0, validator); + // The first step of a transformation is expanding simplified verbs + this.processors.Insert(0, expander); + + // The second step of a transformation is validating the verbs + this.processors.Insert(1, validator); // The successor of each transform processor should be the next one on the list // The last processor defaults to the end of chain processor @@ -46,6 +50,13 @@ public JdtProcessorChain() // If the transformation has a corresponding verb, // add it to the list of verbs to be validated validator.ValidVerbs.Add(successor.Verb); + + if (successor.Expandable) + { + // If the transformation is exapandable, + // add it to the expander valid verbs + expander.ValidVerbs.Add(successor.Verb); + } } processorsEnumerator.Current.Successor = successor; @@ -53,7 +64,7 @@ public JdtProcessorChain() } } - public void Start(JObject source, JObject transform, JsonTransformationContextLogger logger) + public void Start(JToken source, JObject transform, JsonTransformationContextLogger logger) { if (source == null) { @@ -82,7 +93,10 @@ private JdtEndOfChain() public override string Verb { get; } = null; - internal override void Process(JObject source, JObject transform, JsonTransformationContextLogger logger) + /// + public override bool Expandable { get; } = false; + + internal override void Process(JToken source, JObject transform, JsonTransformationContextLogger logger) { // Do nothing, the chain is done } diff --git a/src/Microsoft.VisualStudio.Jdt/Processors/JdtProcessor.cs b/src/Microsoft.VisualStudio.Jdt/Processors/JdtProcessor.cs index 96984e1..c6f774e 100644 --- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtProcessor.cs +++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtProcessor.cs @@ -22,6 +22,11 @@ internal abstract partial class JdtProcessor /// public abstract string Verb { get; } + /// + /// Gets a value indicating whether this processor can be exapnded from simplified form. + /// + public abstract bool Expandable { get; } + /// /// Gets the full verb corresponding the to the transformation. /// @@ -57,7 +62,7 @@ private set /// Object to be transformed. /// Object that specifies the transformation. /// The logger for the transformation. - internal static void ProcessTransform(JObject source, JObject transform, JsonTransformationContextLogger logger) + internal static void ProcessTransform(JToken source, JObject transform, JsonTransformationContextLogger logger) { if (source == null) { @@ -79,6 +84,6 @@ internal static void ProcessTransform(JObject source, JObject transform, JsonTra /// Object to be transformed. /// Object specifying the transformation. /// The logger for the transformation. - internal abstract void Process(JObject source, JObject transform, JsonTransformationContextLogger logger); + internal abstract void Process(JToken source, JObject transform, JsonTransformationContextLogger logger); } } diff --git a/src/Microsoft.VisualStudio.Jdt/Processors/JdtRecurse.cs b/src/Microsoft.VisualStudio.Jdt/Processors/JdtRecurse.cs index 44e5dae..34dc5a7 100644 --- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtRecurse.cs +++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtRecurse.cs @@ -17,7 +17,10 @@ internal class JdtRecurse : JdtProcessor public override string Verb { get; } = null; /// - internal override void Process(JObject source, JObject transform, JsonTransformationContextLogger logger) + public override bool Expandable { get; } = false; + + /// + internal override void Process(JToken source, JObject transform, JsonTransformationContextLogger logger) { if (source == null) { @@ -37,9 +40,10 @@ internal override void Process(JObject source, JObject transform, JsonTransforma { // We recurse into objects that do not correspond to JDT verbs and that exist in both source and transform JToken sourceChild; - if (source.TryGetValue(transformNode.Name, out sourceChild) && sourceChild.Type == JTokenType.Object) + if (source.Type == JTokenType.Object && ((JObject)source).TryGetValue(transformNode.Name, out sourceChild) + && (sourceChild.Type == JTokenType.Object || sourceChild.Type == JTokenType.Array)) { - ProcessTransform((JObject)sourceChild, (JObject)transformNode.Value, logger); + ProcessTransform(sourceChild, (JObject)transformNode.Value, logger); // If we have already recursed into that node, it should be removed from the transform nodesToRemove.Add(transformNode.Name); diff --git a/src/Microsoft.VisualStudio.Jdt/Processors/JdtRemove.cs b/src/Microsoft.VisualStudio.Jdt/Processors/JdtRemove.cs index fb5e875..1c3a358 100644 --- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtRemove.cs +++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtRemove.cs @@ -26,15 +26,21 @@ public JdtRemove() public override string Verb { get; } = "remove"; /// - protected override bool ProcessCore(JObject source, JToken transformValue, JsonTransformationContextLogger logger) + public override bool Expandable { get; } = false; + + /// + protected override bool ProcessCore(JToken source, JToken transformValue, JsonTransformationContextLogger logger) { switch (transformValue.Type) { case JTokenType.String: - // If the value is just a string, remove that node - if (!source.Remove(transformValue.ToString())) + if (source.Type == JTokenType.Object) { - logger.LogWarning(Resources.WarningMessage_UnableToRemove, ErrorLocation.Transform, transformValue); + // If the value is just a string, remove that node + if (!((JObject)source).Remove(transformValue.ToString())) + { + logger.LogWarning(Resources.WarningMessage_UnableToRemove, ErrorLocation.Transform, transformValue); + } } break; @@ -62,7 +68,7 @@ protected override bool ProcessCore(JObject source, JToken transformValue, JsonT return true; } - private bool RemoveWithAttributes(JObject source, JObject removeObject, JsonTransformationContextLogger logger) + private bool RemoveWithAttributes(JToken source, JObject removeObject, JsonTransformationContextLogger logger) { var attributes = this.attributeValidator.ValidateAndReturnAttributes(removeObject); @@ -126,7 +132,7 @@ private bool RemoveWithAttributes(JObject source, JObject removeObject, JsonTran return true; } - private bool RemoveThisNode(JObject nodeToRemove, JsonTransformationContextLogger logger) + private bool RemoveThisNode(JToken nodeToRemove, JsonTransformationContextLogger logger) { var parent = (JProperty)nodeToRemove.Parent; if (parent == null) diff --git a/src/Microsoft.VisualStudio.Jdt/Processors/JdtRename.cs b/src/Microsoft.VisualStudio.Jdt/Processors/JdtRename.cs index 24476f7..905d226 100644 --- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtRename.cs +++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtRename.cs @@ -26,7 +26,10 @@ public JdtRename() public override string Verb { get; } = "rename"; /// - protected override bool ProcessCore(JObject source, JToken transformValue, JsonTransformationContextLogger logger) + public override bool Expandable { get; } = false; + + /// + protected override bool ProcessCore(JToken source, JToken transformValue, JsonTransformationContextLogger logger) { if (transformValue.Type != JTokenType.Object) { @@ -90,7 +93,7 @@ protected override bool ProcessCore(JObject source, JToken transformValue, JsonT // TO DO: Warning if the node is not found JToken nodeToRename; - if (source.TryGetValue(renameOperation.Name, out nodeToRename)) + if (source.Type == JTokenType.Object && ((JObject)source).TryGetValue(renameOperation.Name, out nodeToRename)) { if (!this.RenameNode(nodeToRename, renameOperation.Value.ToString())) { diff --git a/src/Microsoft.VisualStudio.Jdt/Processors/JdtReplace.cs b/src/Microsoft.VisualStudio.Jdt/Processors/JdtReplace.cs index 5602575..b3eb1ff 100644 --- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtReplace.cs +++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtReplace.cs @@ -25,7 +25,10 @@ public JdtReplace() public override string Verb { get; } = "replace"; /// - protected override bool ProcessCore(JObject source, JToken transformValue, JsonTransformationContextLogger logger) + public override bool Expandable { get; } = true; + + /// + protected override bool ProcessCore(JToken source, JToken transformValue, JsonTransformationContextLogger logger) { if (transformValue.Type == JTokenType.Object) { @@ -48,7 +51,7 @@ protected override bool ProcessCore(JObject source, JToken transformValue, JsonT } } - private bool ReplaceWithProperties(JObject source, JObject replaceObject, JsonTransformationContextLogger logger) + private bool ReplaceWithProperties(JToken source, JObject replaceObject, JsonTransformationContextLogger logger) { var attributes = this.attributeValidator.ValidateAndReturnAttributes(replaceObject); diff --git a/src/Microsoft.VisualStudio.Jdt/Processors/JdtValidator.cs b/src/Microsoft.VisualStudio.Jdt/Processors/JdtValidator.cs index 3141a3b..723ce60 100644 --- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtValidator.cs +++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtValidator.cs @@ -22,7 +22,10 @@ internal class JdtValidator : JdtProcessor public override string Verb { get; } = null; /// - internal override void Process(JObject source, JObject transform, JsonTransformationContextLogger logger) + public override bool Expandable { get; } = false; + + /// + internal override void Process(JToken source, JObject transform, JsonTransformationContextLogger logger) { if (source == null) { diff --git a/src/Microsoft.VisualStudio.Jdt/Resources.Designer.cs b/src/Microsoft.VisualStudio.Jdt/Resources.Designer.cs index 3d9aa63..422630a 100644 --- a/src/Microsoft.VisualStudio.Jdt/Resources.Designer.cs +++ b/src/Microsoft.VisualStudio.Jdt/Resources.Designer.cs @@ -20,7 +20,7 @@ namespace Microsoft.VisualStudio.Jdt { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Resources { @@ -97,6 +97,15 @@ internal static string ErrorMessage_InvalidAttributes { } } + /// + /// Looks up a localized string similar to {0} is not a valid JDT inline verb. + /// + internal static string ErrorMessage_InvalidInlineVerb { + get { + return ResourceManager.GetString("ErrorMessage_InvalidInlineVerb", resourceCulture); + } + } + /// /// Looks up a localized string similar to {0} is not a valid transform value for Remove. /// diff --git a/src/Microsoft.VisualStudio.Jdt/Resources.resx b/src/Microsoft.VisualStudio.Jdt/Resources.resx index 6280314..f023bbc 100644 --- a/src/Microsoft.VisualStudio.Jdt/Resources.resx +++ b/src/Microsoft.VisualStudio.Jdt/Resources.resx @@ -133,6 +133,9 @@ Invalid transformation attributes The error message to be displayed if invalid attributes are found + + {0} is not a valid JDT inline verb + {0} is not a valid transform value for Remove The error message to be displayed when an invalid remove value is applied