From 9df54667f1d1286d485a0714362f6492e79baa32 Mon Sep 17 00:00:00 2001 From: Jakub Tomkiewicz Date: Fri, 14 Jan 2022 17:55:08 +0100 Subject: [PATCH 1/4] Better support for arrays. Added wiki examples, 4 of which are failing. --- .../Inputs/Default/WikiExample.Source.json | 8 +++ .../Default/WikiExample.Test.Expected.json | 16 ++++++ .../Default/WikiExample.Test.Transform.json | 9 ++++ .../Inputs/Merge/WikiExample.Source.json | 27 ++++++++++ .../Merge/WikiExample.Test.Expected.json | 34 +++++++++++++ .../Merge/WikiExample.Test.Transform.json | 28 +++++++++++ .../SimpleArray.RemoveWhole.Expected.json | 10 ++++ .../SimpleArray.RemoveWhole.Transform.json | 5 ++ .../Inputs/Remove/SimpleArray.Source.json | 14 ++++++ .../Inputs/Remove/WikiExample.Source.json | 14 ++++++ .../Remove/WikiExample.Test.Expected.json | 11 +++++ .../Remove/WikiExample.Test.Transform.json | 9 ++++ .../Inputs/Remove/WikiExample2.Source.json | 14 ++++++ .../Remove/WikiExample2.Test.Expected.json | 10 ++++ .../Remove/WikiExample2.Test.Transform.json | 12 +++++ .../Inputs/Rename/WikiExample.Source.json | 14 ++++++ .../Rename/WikiExample.Test.Expected.json | 17 +++++++ .../Rename/WikiExample.Test.Transform.json | 6 +++ .../Inputs/Rename/WikiExample2.Source.json | 18 +++++++ .../Rename/WikiExample2.Test.Expected.json | 21 ++++++++ .../Rename/WikiExample2.Test.Transform.json | 12 +++++ .../Inputs/Replace/SimpleArray.Source.json | 14 ++++++ .../SimpleArray.WithArray.Expected.json | 13 +++++ .../SimpleArray.WithArray.Transform.json | 10 ++++ .../Inputs/Replace/WikiExample.Source.json | 13 +++++ .../Replace/WikiExample.Test.Expected.json | 15 ++++++ .../Replace/WikiExample.Test.Transform.json | 25 ++++++++++ .../Inputs/Replace/WikiExample2.Source.json | 14 ++++++ .../Replace/WikiExample2.Test.Expected.json | 15 ++++++ .../Replace/WikiExample2.Test.Transform.json | 14 ++++++ .../TransformTest.cs | 2 +- .../Processors/JdtArrayProcessor.cs | 6 +-- .../Processors/JdtDefault.cs | 49 +++++++++++-------- .../Processors/JdtMerge.cs | 6 +-- .../Processors/JdtProcessor.ProcessorChain.cs | 4 +- .../Processors/JdtProcessor.cs | 4 +- .../Processors/JdtRecurse.cs | 7 +-- .../Processors/JdtRemove.cs | 15 +++--- .../Processors/JdtRename.cs | 4 +- .../Processors/JdtReplace.cs | 4 +- .../Processors/JdtValidator.cs | 2 +- 41 files changed, 499 insertions(+), 46 deletions(-) create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/WikiExample.Source.json create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/WikiExample.Test.Expected.json create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/WikiExample.Test.Transform.json create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/WikiExample.Source.json create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/WikiExample.Test.Expected.json create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/WikiExample.Test.Transform.json create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/SimpleArray.RemoveWhole.Expected.json create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/SimpleArray.RemoveWhole.Transform.json create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/SimpleArray.Source.json create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/WikiExample.Source.json create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/WikiExample.Test.Expected.json create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/WikiExample.Test.Transform.json create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/WikiExample2.Source.json create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/WikiExample2.Test.Expected.json create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/WikiExample2.Test.Transform.json create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/WikiExample.Source.json create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/WikiExample.Test.Expected.json create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/WikiExample.Test.Transform.json create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/WikiExample2.Source.json create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/WikiExample2.Test.Expected.json create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/WikiExample2.Test.Transform.json create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/SimpleArray.Source.json create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/SimpleArray.WithArray.Expected.json create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/SimpleArray.WithArray.Transform.json create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/WikiExample.Source.json create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/WikiExample.Test.Expected.json create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/WikiExample.Test.Transform.json create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/WikiExample2.Source.json create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/WikiExample2.Test.Expected.json create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/WikiExample2.Test.Transform.json 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 00000000..555f1cef --- /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 00000000..ba4defe6 --- /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 00000000..fcc9c085 --- /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/WikiExample.Source.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/WikiExample.Source.json new file mode 100644 index 00000000..d2eab530 --- /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 00000000..10feb74b --- /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 00000000..e52cc809 --- /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": "$[?(@.TransformThis == true)]", + "@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 00000000..c1422429 --- /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 00000000..5c7d3cd4 --- /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 00000000..c0f5bd17 --- /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 00000000..c918ff01 --- /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 00000000..c428c429 --- /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 00000000..18e11a74 --- /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 00000000..728cc4e4 --- /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 00000000..3c62d5bc --- /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 00000000..2e3434b4 --- /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": "$[?(@.RemoveThis == true)]" + }, + "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/WikiExample.Source.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/WikiExample.Source.json new file mode 100644 index 00000000..404f0cbd --- /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 00000000..d600ac2f --- /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 00000000..7191ff7d --- /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 00000000..d4a6ef7a --- /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 00000000..3654a3f1 --- /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 00000000..e95a2740 --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/WikiExample2.Test.Transform.json @@ -0,0 +1,12 @@ +{ + "@jdt.rename": { + "@jdt.path": "$[?(@.Rename == true)]", + "@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/SimpleArray.Source.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/SimpleArray.Source.json new file mode 100644 index 00000000..04bd771c --- /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 00000000..d621b174 --- /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 00000000..a8d22730 --- /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 00000000..d4c59962 --- /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 00000000..0e123767 --- /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 00000000..fea08d65 --- /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 00000000..e6dd4814 --- /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 00000000..349903cb --- /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 00000000..669b05ea --- /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/TransformTest.cs b/src/Microsoft.VisualStudio.Jdt.Tests/TransformTest.cs index 317e7439..cb2cbd5a 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/Processors/JdtArrayProcessor.cs b/src/Microsoft.VisualStudio.Jdt/Processors/JdtArrayProcessor.cs index 7561be80..06dba84c 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 4da52d4a..ecb8c1a3 100644 --- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtDefault.cs +++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtDefault.cs @@ -3,9 +3,9 @@ namespace Microsoft.VisualStudio.Jdt { + using Newtonsoft.Json.Linq; using System; using System.Linq; - using Newtonsoft.Json.Linq; /// /// Represents the default JDT transformation. @@ -16,7 +16,7 @@ internal class JdtDefault : JdtProcessor public override string Verb { get; } = null; /// - internal override void Process(JObject source, JObject transform, JsonTransformationContextLogger logger) + internal override void Process(JToken source, JObject transform, JsonTransformationContextLogger logger) { if (source == null) { @@ -28,32 +28,39 @@ 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() - .Where(p => !JdtUtilities.IsJdtSyntax(p.Name))) + if (source.Type == JTokenType.Object) { - JToken nodeToTransform; - if (source.TryGetValue(transformNode.Name, out nodeToTransform)) + // JDT Verbs are not handled here + foreach (JProperty transformNode in transform.Properties() + .Where(p => !JdtUtilities.IsJdtSyntax(p.Name))) { - // 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) + JToken nodeToTransform; + if (((JObject)source).TryGetValue(transformNode.Name, out nodeToTransform)) { - // If the original and transform are arrays, merge the contents together - ((JArray)nodeToTransform).Merge(transformNode.Value.DeepClone()); + // 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 the contents together + ((JArray)nodeToTransform).Merge(transformNode.Value.DeepClone()); + } + else if (nodeToTransform.Type != JTokenType.Object || transformNode.Value.Type != JTokenType.Object) + { + // 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(); + } } - else if (nodeToTransform.Type != JTokenType.Object || transformNode.Value.Type != JTokenType.Object) + else { - // 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(); + // If the node is not present in the original, add it + ((JObject)source).Add(transformNode.DeepClone()); } } - else - { - // If the node is not present in the original, add it - source.Add(transformNode.DeepClone()); - } + } + else if (!transform.Properties().Where(p => JdtUtilities.IsJdtSyntax(p.Name)).Any()) + { + source.Replace(transform.DeepClone()); } 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 3a9d1d2d..e778c4a2 100644 --- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtMerge.cs +++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtMerge.cs @@ -26,13 +26,13 @@ public JdtMerge() public override string Verb { get; } = "merge"; /// - protected override bool ProcessCore(JObject source, JToken transformValue, JsonTransformationContextLogger logger) + 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 556d9c5a..8b00e4b5 100644 --- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtProcessor.ProcessorChain.cs +++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtProcessor.ProcessorChain.cs @@ -53,7 +53,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 +82,7 @@ private JdtEndOfChain() public override string Verb { get; } = null; - internal override void Process(JObject source, JObject transform, JsonTransformationContextLogger logger) + 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 96984e14..44b82c8a 100644 --- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtProcessor.cs +++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtProcessor.cs @@ -57,7 +57,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 +79,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 44e5dae7..bf5aaefb 100644 --- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtRecurse.cs +++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtRecurse.cs @@ -17,7 +17,7 @@ internal class JdtRecurse : JdtProcessor public override string Verb { get; } = null; /// - internal override void Process(JObject source, JObject transform, JsonTransformationContextLogger logger) + internal override void Process(JToken source, JObject transform, JsonTransformationContextLogger logger) { if (source == null) { @@ -37,9 +37,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 fb5e8751..607c83ee 100644 --- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtRemove.cs +++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtRemove.cs @@ -26,15 +26,18 @@ public JdtRemove() public override string Verb { get; } = "remove"; /// - protected override bool ProcessCore(JObject source, JToken transformValue, JsonTransformationContextLogger logger) + 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 +65,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 +129,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 24476f72..c3c6004f 100644 --- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtRename.cs +++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtRename.cs @@ -26,7 +26,7 @@ public JdtRename() public override string Verb { get; } = "rename"; /// - protected override bool ProcessCore(JObject source, JToken transformValue, JsonTransformationContextLogger logger) + protected override bool ProcessCore(JToken source, JToken transformValue, JsonTransformationContextLogger logger) { if (transformValue.Type != JTokenType.Object) { @@ -90,7 +90,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 56025753..8a6a40f5 100644 --- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtReplace.cs +++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtReplace.cs @@ -25,7 +25,7 @@ public JdtReplace() public override string Verb { get; } = "replace"; /// - protected override bool ProcessCore(JObject source, JToken transformValue, JsonTransformationContextLogger logger) + protected override bool ProcessCore(JToken source, JToken transformValue, JsonTransformationContextLogger logger) { if (transformValue.Type == JTokenType.Object) { @@ -48,7 +48,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 3141a3b7..36da26b2 100644 --- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtValidator.cs +++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtValidator.cs @@ -22,7 +22,7 @@ internal class JdtValidator : JdtProcessor public override string Verb { get; } = null; /// - internal override void Process(JObject source, JObject transform, JsonTransformationContextLogger logger) + internal override void Process(JToken source, JObject transform, JsonTransformationContextLogger logger) { if (source == null) { From 545fec1e273581fc0b4e24b289aaebbef02a64e2 Mon Sep 17 00:00:00 2001 From: Jakub Tomkiewicz Date: Wed, 19 Jun 2024 21:05:18 +0200 Subject: [PATCH 2/4] Handle JDT Verbs inside of default merge objects --- .../Merge/Object.MissingPath.Expected.json | 18 +++++ .../Merge/Object.MissingPath.Transform.json | 17 +++++ .../Merge/WikiExample.Test.Transform.json | 6 +- .../Remove/WikiExample2.Test.Transform.json | 4 +- .../Rename/Array.MissingPath.Expected.json | 15 ++++ .../Rename/Array.MissingPath.Transform.json | 8 ++ .../Rename/Array.ScriptPath.Expected.json | 8 +- ... .json => Array.ScriptPath.Transform.json} | 2 +- .../Rename/WikiExample2.Test.Transform.json | 4 +- .../Replace/Array.MissingPath.Expected.json | 18 +++++ .../Replace/Array.MissingPath.Transform.json | 10 +++ .../Replace/WikiExample2.Test.Transform.json | 2 +- .../Microsoft.VisualStudio.Jdt.Tests.csproj | 2 +- .../Processors/JdtDefault.cs | 73 ++++++++++++++++++- 14 files changed, 171 insertions(+), 16 deletions(-) create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.MissingPath.Expected.json create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.MissingPath.Transform.json create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.MissingPath.Expected.json create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.MissingPath.Transform.json rename src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/{Array.ScriptPath.Transform .json => Array.ScriptPath.Transform.json} (51%) create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.MissingPath.Expected.json create mode 100644 src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.MissingPath.Transform.json 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 00000000..a4ef4083 --- /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 00000000..c9be6eb7 --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.MissingPath.Transform.json @@ -0,0 +1,17 @@ +{ + "D": { + "@jdt.merge": 4 + }, + "E": [ + { + "E1": { + "@jdt.merge": 5 + } + }, + { + "E2": { + "@jdt.merge": 6 + } + } + ] +} 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 index e52cc809..5aae52ec 100644 --- a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/WikiExample.Test.Transform.json +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/WikiExample.Test.Transform.json @@ -2,14 +2,14 @@ //Executes for all nodes on this level "@jdt.merge": [ { - "@jdt.path": "$.*", + "@jdt.path": "*", "@jdt.value": { "Default": 0 } }, //This only executes for matching nodes { - "@jdt.path": "$[?(@.TransformThis == true)]", + "@jdt.path": "A", "@jdt.value": { "Transformed": true } @@ -18,7 +18,7 @@ "E": { // Accessing objects in array "@jdt.merge": { - "@jdt.path": "$.Items[?(@.Value < 15)]", + "@jdt.path": "Items[?(@.Value < 15)]", "@jdt.value": { "Value": 15, "Changed": true 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 index 2e3434b4..df80552f 100644 --- a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/WikiExample2.Test.Transform.json +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/WikiExample2.Test.Transform.json @@ -1,12 +1,12 @@ { //Remove only matching nodes from this level "@jdt.remove": { - "@jdt.path": "$[?(@.RemoveThis == true)]" + "@jdt.path": "A" }, "C": { //Specify a relative path to the node "@jdt.remove": { - "@jdt.path": "@.C2.C21" + "@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 00000000..49444008 --- /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 00000000..6547ef41 --- /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 c0d2dce4..f3a5019e 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 54a91db2..200a5950 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/WikiExample2.Test.Transform.json b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/WikiExample2.Test.Transform.json index e95a2740..b881fb10 100644 --- a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/WikiExample2.Test.Transform.json +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/WikiExample2.Test.Transform.json @@ -1,11 +1,11 @@ { "@jdt.rename": { - "@jdt.path": "$[?(@.Rename == true)]", + "@jdt.path": "A", "@jdt.value": "Astar" }, "C": { "@jdt.rename": { - "@jdt.path": "@[*].Name", + "@jdt.path": "[*].Name", "@jdt.value": "Nstar" } } 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 00000000..8ec82c41 --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.MissingPath.Expected.json @@ -0,0 +1,18 @@ +{ + "A": [ + { "Index": 1 }, + { "Index": 2 }, + { "Index": 3 } + ], + "B": [ + { "Replace": true }, + { "Replace": false }, + { "Replace": "WrongValue" }, + { "HasReplace": true }, + { "Replace": true } + ], + "C": [ + 1, + 2 + ] +} 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 00000000..c5ca1d77 --- /dev/null +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.MissingPath.Transform.json @@ -0,0 +1,10 @@ +{ + "C": { + "@jdt.replace": [ + [ + 1, + 2 + ] + ] + } +} 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 index 669b05ea..4cbe52e2 100644 --- a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/WikiExample2.Test.Transform.json +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/WikiExample2.Test.Transform.json @@ -5,7 +5,7 @@ }, "B": { "@jdt.replace": { - "@jdt.path": "@[?(@.ReplaceThis == true)]", + "@jdt.path": "[?(@.ReplaceThis == true)]", "@jdt.value": { "Replaced": true } 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 666def7b..37d7b813 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/Processors/JdtDefault.cs b/src/Microsoft.VisualStudio.Jdt/Processors/JdtDefault.cs index ecb8c1a3..d33fe081 100644 --- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtDefault.cs +++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtDefault.cs @@ -6,12 +6,21 @@ namespace Microsoft.VisualStudio.Jdt using Newtonsoft.Json.Linq; using System; using System.Linq; + using System.Xml.Linq; /// /// Represents the default JDT transformation. /// internal class JdtDefault : JdtProcessor { + private DefaultMode mode = DefaultMode.Merge; + + private enum DefaultMode + { + Merge, + Replace, + } + /// public override string Verb { get; } = null; @@ -41,8 +50,15 @@ internal override void Process(JToken source, JObject transform, JsonTransformat // 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 the contents together - ((JArray)nodeToTransform).Merge(transformNode.Value.DeepClone()); + // If the original and transform are arrays, merge or replace the contents, depending on current mode + if (this.mode == DefaultMode.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) { @@ -53,6 +69,23 @@ internal override void Process(JToken source, JObject transform, JsonTransformat } else { + var shouldResetMode = this.mode == DefaultMode.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.mode = DefaultMode.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.mode = DefaultMode.Merge; + } + // If the node is not present in the original, add it ((JObject)source).Add(transformNode.DeepClone()); } @@ -65,5 +98,41 @@ internal override void Process(JToken source, JObject transform, JsonTransformat 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()) + { + 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() + .Where(p => JdtUtilities.IsJdtSyntax(p.Name)).ToArray()) + { + jObject.Remove(node.Name); + } + + ProcessTransform(token, selfTransform, logger); + + foreach (JProperty node in jObject.Properties().ToArray()) + { + this.ProcessTransformAndCleanJdtProperties(node.Value, logger); + } + } + + return token; + } } } From a8849e660bff29fac290a6156a2a0536c084270a Mon Sep 17 00:00:00 2001 From: Jakub Tomkiewicz Date: Fri, 21 Jun 2024 16:28:08 +0200 Subject: [PATCH 3/4] Simplified inline transform verbs --- .../Merge/Object.MissingPath.Transform.json | 4 +- .../Replace/Array.MissingPath.Expected.json | 16 ++++- .../Replace/Array.MissingPath.Transform.json | 18 ++++++ .../JdtDefaultTransform.cs | 18 ++++++ .../JdtUtilities.cs | 36 ++++++++++- .../Processors/JdtDefault.cs | 39 ++++++----- .../Processors/JdtExpander.cs | 64 +++++++++++++++++++ .../Processors/JdtMerge.cs | 3 + .../Processors/JdtProcessor.ProcessorChain.cs | 18 +++++- .../Processors/JdtProcessor.cs | 5 ++ .../Processors/JdtRecurse.cs | 3 + .../Processors/JdtRemove.cs | 3 + .../Processors/JdtRename.cs | 3 + .../Processors/JdtReplace.cs | 3 + .../Processors/JdtValidator.cs | 3 + .../Resources.Designer.cs | 11 +++- src/Microsoft.VisualStudio.Jdt/Resources.resx | 3 + 17 files changed, 225 insertions(+), 25 deletions(-) create mode 100644 src/Microsoft.VisualStudio.Jdt/JdtDefaultTransform.cs create mode 100644 src/Microsoft.VisualStudio.Jdt/Processors/JdtExpander.cs 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 index c9be6eb7..e9181166 100644 --- a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.MissingPath.Transform.json +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.MissingPath.Transform.json @@ -9,9 +9,7 @@ } }, { - "E2": { - "@jdt.merge": 6 - } + "E2@jdt.merge": 6 } ] } 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 index 8ec82c41..4207bbec 100644 --- a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.MissingPath.Expected.json +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.MissingPath.Expected.json @@ -14,5 +14,19 @@ "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 index c5ca1d77..58edf06d 100644 --- a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.MissingPath.Transform.json +++ b/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.MissingPath.Transform.json @@ -6,5 +6,23 @@ 2 ] ] + }, + "D@jdt.replace": [ + 3, + 4 + ], + "E": { + "E1": { + "@jdt.replace": [ + [ + 5, + 6 + ] + ] + }, + "E2@jdt.replace": [ + 7, + 8 + ] } } diff --git a/src/Microsoft.VisualStudio.Jdt/JdtDefaultTransform.cs b/src/Microsoft.VisualStudio.Jdt/JdtDefaultTransform.cs new file mode 100644 index 00000000..b9f1fe95 --- /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 f0a45ade..6c491718 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/Processors/JdtDefault.cs b/src/Microsoft.VisualStudio.Jdt/Processors/JdtDefault.cs index d33fe081..3434a48c 100644 --- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtDefault.cs +++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtDefault.cs @@ -3,27 +3,24 @@ namespace Microsoft.VisualStudio.Jdt { - using Newtonsoft.Json.Linq; using System; using System.Linq; using System.Xml.Linq; + using Newtonsoft.Json.Linq; /// /// Represents the default JDT transformation. /// internal class JdtDefault : JdtProcessor { - private DefaultMode mode = DefaultMode.Merge; - - private enum DefaultMode - { - Merge, - Replace, - } + private JdtDefaultTransform defaultTransform = JdtDefaultTransform.Merge; /// public override string Verb { get; } = null; + /// + public override bool Expandable { get; } = false; + /// internal override void Process(JToken source, JObject transform, JsonTransformationContextLogger logger) { @@ -51,7 +48,7 @@ internal override void Process(JToken source, JObject transform, JsonTransformat 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.mode == DefaultMode.Merge) + if (this.defaultTransform == JdtDefaultTransform.Merge) { ((JArray)nodeToTransform).Merge(transformNode.Value.DeepClone()); } @@ -62,19 +59,18 @@ internal override void Process(JToken source, JObject transform, JsonTransformat } else if (nodeToTransform.Type != JTokenType.Object || transformNode.Value.Type != JTokenType.Object) { - // 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 + // For non-arrays and non-objects, just replace them source[transformNode.Name] = transformNode.Value.DeepClone(); } } else { - var shouldResetMode = this.mode == DefaultMode.Merge; + 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.mode = DefaultMode.Replace; + this.defaultTransform = JdtDefaultTransform.Replace; } // If the tranform node is an object, cleaning it and transforming it on itself resolves all remaining JDT Verbs @@ -83,7 +79,7 @@ internal override void Process(JToken source, JObject transform, JsonTransformat if (shouldResetMode) { - this.mode = DefaultMode.Merge; + this.defaultTransform = JdtDefaultTransform.Merge; } // If the node is not present in the original, add it @@ -118,10 +114,19 @@ private JToken ProcessTransformAndCleanJdtProperties(JToken token, JsonTransform { var jObject = (JObject)token; var selfTransform = (JObject)jObject.DeepClone(); - foreach (JProperty node in jObject.Properties() - .Where(p => JdtUtilities.IsJdtSyntax(p.Name)).ToArray()) + foreach (JProperty node in jObject.Properties().ToArray()) { - jObject.Remove(node.Name); + if (JdtUtilities.IsJdtSyntax(node.Name)) + { + // Rename any JDT verb nodes + jObject.Remove(node.Name); + } + else if (JdtUtilities.IsJdtInlineSyntax(node.Name)) + { + // 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())); + } } ProcessTransform(token, selfTransform, logger); diff --git a/src/Microsoft.VisualStudio.Jdt/Processors/JdtExpander.cs b/src/Microsoft.VisualStudio.Jdt/Processors/JdtExpander.cs new file mode 100644 index 00000000..2d4f7aca --- /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 e778c4a2..1af72f2f 100644 --- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtMerge.cs +++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtMerge.cs @@ -25,6 +25,9 @@ public JdtMerge() /// public override string Verb { get; } = "merge"; + /// + public override bool Expandable { get; } = true; + /// protected override bool ProcessCore(JToken source, JToken transformValue, JsonTransformationContextLogger logger) { diff --git a/src/Microsoft.VisualStudio.Jdt/Processors/JdtProcessor.ProcessorChain.cs b/src/Microsoft.VisualStudio.Jdt/Processors/JdtProcessor.ProcessorChain.cs index 8b00e4b5..48225aa9 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; @@ -82,6 +93,9 @@ private JdtEndOfChain() public override string Verb { get; } = null; + /// + 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 44b82c8a..c6f774e1 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. /// diff --git a/src/Microsoft.VisualStudio.Jdt/Processors/JdtRecurse.cs b/src/Microsoft.VisualStudio.Jdt/Processors/JdtRecurse.cs index bf5aaefb..34dc5a7e 100644 --- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtRecurse.cs +++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtRecurse.cs @@ -16,6 +16,9 @@ internal class JdtRecurse : JdtProcessor /// public override string Verb { get; } = null; + /// + public override bool Expandable { get; } = false; + /// internal override void Process(JToken source, JObject transform, JsonTransformationContextLogger logger) { diff --git a/src/Microsoft.VisualStudio.Jdt/Processors/JdtRemove.cs b/src/Microsoft.VisualStudio.Jdt/Processors/JdtRemove.cs index 607c83ee..1c3a358d 100644 --- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtRemove.cs +++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtRemove.cs @@ -25,6 +25,9 @@ public JdtRemove() /// public override string Verb { get; } = "remove"; + /// + public override bool Expandable { get; } = false; + /// protected override bool ProcessCore(JToken source, JToken transformValue, JsonTransformationContextLogger logger) { diff --git a/src/Microsoft.VisualStudio.Jdt/Processors/JdtRename.cs b/src/Microsoft.VisualStudio.Jdt/Processors/JdtRename.cs index c3c6004f..905d2265 100644 --- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtRename.cs +++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtRename.cs @@ -25,6 +25,9 @@ public JdtRename() /// public override string Verb { get; } = "rename"; + /// + public override bool Expandable { get; } = false; + /// protected override bool ProcessCore(JToken source, JToken transformValue, JsonTransformationContextLogger logger) { diff --git a/src/Microsoft.VisualStudio.Jdt/Processors/JdtReplace.cs b/src/Microsoft.VisualStudio.Jdt/Processors/JdtReplace.cs index 8a6a40f5..b3eb1ffd 100644 --- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtReplace.cs +++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtReplace.cs @@ -24,6 +24,9 @@ public JdtReplace() /// public override string Verb { get; } = "replace"; + /// + public override bool Expandable { get; } = true; + /// protected override bool ProcessCore(JToken source, JToken transformValue, JsonTransformationContextLogger logger) { diff --git a/src/Microsoft.VisualStudio.Jdt/Processors/JdtValidator.cs b/src/Microsoft.VisualStudio.Jdt/Processors/JdtValidator.cs index 36da26b2..723ce601 100644 --- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtValidator.cs +++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtValidator.cs @@ -21,6 +21,9 @@ internal class JdtValidator : JdtProcessor /// public override string Verb { get; } = null; + /// + public override bool Expandable { get; } = false; + /// internal override void Process(JToken source, JObject transform, JsonTransformationContextLogger logger) { diff --git a/src/Microsoft.VisualStudio.Jdt/Resources.Designer.cs b/src/Microsoft.VisualStudio.Jdt/Resources.Designer.cs index 3d9aa63d..422630a3 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 6280314e..f023bbc2 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 From 23743b2c2f7608dcd288a6a96b96da1a23e6e2a7 Mon Sep 17 00:00:00 2001 From: Jakub Tomkiewicz Date: Fri, 21 Jun 2024 16:28:40 +0200 Subject: [PATCH 4/4] Added JsonTransformationMemoryLogger --- .../JsonTransformationMemoryLogger.cs | 159 ++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 src/Microsoft.VisualStudio.Jdt/JsonTransformationMemoryLogger.cs diff --git a/src/Microsoft.VisualStudio.Jdt/JsonTransformationMemoryLogger.cs b/src/Microsoft.VisualStudio.Jdt/JsonTransformationMemoryLogger.cs new file mode 100644 index 00000000..1378c377 --- /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; } + } + } +}