Repository files navigation

JSON Icon JsonPeek and JsonPoke MSBuild Tasks

LicenseBuild

JsonPeek Icon JsonPeek

VersionDownloads

Read values from JSON using JSONPath.

Usage:

 <JsonPeekContentPath="[JSON_FILE]"Query="[JSONPath]">
<OutputTaskParameter="Result"PropertyName="Value" />
</JsonPeek>
<JsonPeekContent="[JSON]"Query="[JSONPath]">
<OutputTaskParameter="Result"ItemName="Values" />
</JsonPeek>

Parameters:

ParameterDescription
ContentOptional string parameter.
Specifies the JSON input as a string.
ContentPathOptional ITaskItem parameter.
Specifies the JSON input as a file path.
EmptyOptional string parameter.
Value to use as a replacement for empty values matched in JSON.
QueryRequired string parameter.
Specifies the JSONPath expression.
ResultOutput ITaskItem[] parameter.
Contains the results that are returned by the task.

You can either provide the path to a JSON file via ContentPath or provide the straight JSON content to Content. The Query is a JSONPath expression that is evaluated and returned via the Result task parameter. You can assign the resulting value to either a property (i.e. for a single value) or an item name (i.e. for multiple results).

JSON object properties are automatically projected as item metadata when assigning the resulting value to an item. For example, given the following JSON:

{
"http": {
"host": "localhost",
"port": 80,
"ssl": true
}
}

You can read the entire http value as an item with each property as a metadata value with:

<JsonPeekContentPath="host.json"Query="$.http">
<OutputTaskParameter="Result"ItemName="Http" />
</JsonPeek>

The Http item will have the following values (if it were declared in MSBuild):

<ItemGroup>
<HttpInclude="[item raw json]">
<host>localhost</host>
<port>80</port>
<ssl>true</ssl>
</Http>
</ItemGroup>

These item metadata values could be read as MSBuild properties as follows, for example:

<PropertyGroup>
<Host>@(Http -> '%(host)')</Host>
<Port>@(Http -> '%(port)')</Port>
<Ssl>@(Http -> '%(ssl)')</Ssl>
</PropertyGroup>

In addition to the explicitly opted in object properties, the entire node is available as raw JSON via the special _ (single underscore) metadata item.

If the matched value is empty, no items (because items cannot be constructed with empty identity) or property value will be returned. This makes it difficult to distinguish a successfully matched empty value from no value matched at all. For these cases, it's possible to specify an Empty value to stand-in for an empty (but successful) matched result instead, which allow to distinguish both scenarios:

<JsonPeekContent="$(Json)"Empty="$empty"Query="$(Query)">
<OutputTaskParameter="Result"PropertyName="Value" />
</JsonPeek>
<ErrorCondition="'$(Value)' == '$empty'"Text="The element $(Query) cannot have an empty value." />

JsonPoke Icon JsonPoke

VersionDownloads

Write values to JSON nodes selected with JSONPath

Usage:

 <JsonPokeContentPath="[JSON_FILE]"Query="[JSONPath]"Value="[VALUE]" />
<JsonPokeContentPath="[JSON_FILE]"Query="[JSONPath]"RawValue="[JSON]" />
<JsonPokeContent="[JSON]"Query="[JSONPath]"Value="[VALUE]" />

Parameters:

ParameterDescription
ContentOptional string input/output parameter.
Specifies the JSON input as a string and contains the updated
JSON after successful task execution.
ContentPathOptional ITaskItem parameter.
Specifies the JSON input as a file path.
QueryRequired string parameter.
Specifies the JSONPath expression.
ValueOptional ITaskItem[] parameter.
Specifies the value(s) to be inserted into the specified path.
RawValueOptional string parameter.
Specifies the raw (JSON) value to be inserted into the specified path.

You must either provide the path to a JSON file via ContentPath or raw JSON content via Content.

The Value can be an item group, and in that case, it will be inserted into the JSON node matching the JSONPath expression Query as an array. RawValue can be used to provide an entire JSON fragment as a string, with no conversion to an MSBuild item at all.

The existing JSON node will determine the data type of the value being written, so as to preserve the original document. Numbers, booleans and DateTimes are properly parsed before serializing to the node.

 <PropertyGroup>
<Json>
{
"http": {
"host": "localhost",
"port": 80,
"ssl": true
}
}
</Json>
</PropertyGroup>
<JsonPokeContent="$(Json)"Query="$.http.host"Value="example.com">
<OutputTaskParameter="Content"PropertyName="Json" />
</JsonPoke>
<JsonPokeContent="$(Json)"Query="$.http.port"Value="80">
<OutputTaskParameter="Content"PropertyName="Json" />
</JsonPoke>
<JsonPokeContent="$(Json)"Query="$.http.ssl"Value="true">
<OutputTaskParameter="Content"PropertyName="Json" />
</JsonPoke>
<MessageImportance="high"Text="$(Json)" />

Note how we update multiple values and assign the updated content to the same $(Json) property so it can be used in subsequent updates. The last Message task will render the following JSON:

{
"http": {
"host": "example.com",
"port": 80,
"ssl": true
}
}

NOTE: The port number was preserved as a number, as is the ssl boolean.

To force a value to be interpreted as a string, you can surround it with double or single quotes. For example, given the following JSON file:

{
"http": {
"ports": [
"80"
]
}
}

We can replace the ports array with string values as follows (without the explicit quotes, the values would be interpreted as numbers otherwise):

 <ItemGroup>
<HttpPortInclude="'8080'" />
<HttpPortInclude="'1080'" />
</ItemGroup>
<JsonPokeContentPath="http.json"Query="$.http.ports"Value="@(HttpPort)" />

Result:

{
"http": {
"ports": [
"8080", "1080"
]
}
}

It's also possible to write a complex object based on MSBuild item metadata:

 <ItemGroup>
<HttpInclude="Value">
<host>localhost</host>
<port>80</port>
<ssl>true</ssl>
</Value>
</ItemGroup>
<JsonPokeContentPath="http.json"Query="$.http"Value="@(Http)"Properties="host;port;ssl" />

Result:

{
"http": {
"host": "localhost",
"port": 80,
"ssl": true
}
}

Note how the native JSON type was automatically inferred, even though everything is basically a string in MSBuild. As noted above, you can surround any of the item metadata values in double or single quotes to force them to be written as strings instead.

The task can create entire object hierarchies if any segment of the path expression is not found, which makes it very easy to create complex structures by assigning a single value. For example, if the http section in the examples above didn't exist at all, the following task would add it automatically, prior to assigning the ssl property to true:

<JsonPokeContentPath="http.json"Query="$.http.ssl"Value="true" />

This also works for indexed queries, such as adding launch profile to launchSettings.json by simply assigning a value:

<JsonPokeContentPath="Properties\launchSettings.json"Query="$.profiles['IIS Express'].commandName"Value="IISExpress" />

which would create the following entry:

{
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
}
}
}

Array index is also supported as part of the query, to modify existing values. If the array is empty or non-existent, it's also possible to just use the index [0] to denote the new node should be the sole element in the new array, like for adding a new watch file value to host.json:

<JsonPokeContentPath="host.json"Query="$.watchFiles[0]"Value="myFile.txt" />

Which results in:

{
..."watchFiles": [ "myFile.txt" ]
}

It's quite common to want to add entries to an existing array, usually at the end of the array. The JSONPath syntax supports indexes that start from the end of the array (such as [-1:]), but if the array had any values already, that would match whichever is the last element, meaning in an update to that element's value. Since we need a different syntax for inserting a new node, starting from the end of the list, we leverage the C# syntax ^n where n is the position starting from the end. To add a new element at the end of the list, the index [^1] can be used. ^2 means prior to last and so on.

For example, to add a new watched file to the array in the example above, we could use:

<JsonPokeContentPath="host.json"Query="$.watchFiles[^1]"Value="myOtherFile.txt" />

Given an existing host.json file like the one above, we would get a new file added like so:

{
..."watchFiles": [ "myFile.txt", "myOtherFile.txt" ]
}

If the watchFiles property didn't exit at all or had no elements, the result would be the same as if we used [0], but this makes the code more flexible if needed.

The modified JSON nodes can be assigned to an item name using the Result task property, and will contain the item path (matching the Query plus the index if multiple nodes were modified) as well as the Value item metadata containing the raw JSON that was written.

Dogfooding

CI VersionBuild

We also produce CI packages from branches and pull requests so you can dogfood builds as quickly as they are produced.

The CI feed is https://pkg.kzu.app/index.json.

The versioning scheme for packages is:

  • PR builds: 42.42.42-pr[NUMBER]
  • Branch builds: 42.42.42-[BRANCH].[COMMITS]

Sponsors

Clarius OrgMFB Technologies, Inc.SandRockDRIVE.NET, Inc.Keith PickfordThomas BolonKori FrancisReuben SwartzJacob FosheeEric JohnsonJonathan Ken BonnySimon Croppagileworks-euZheyu ShenVezelChilliCream4OTCdomischellAdrian AlonsotorutekRyan McCafferySeika LogicielAndrew Granteska-gmbhGeodata AS

Sponsor this project

Learn more about GitHub Sponsors

About

JsonPeek and JsonPoke tasks implementations

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

11 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

JSON Icon JsonPeek and JsonPoke MSBuild Tasks

LicenseBuild

JsonPeek Icon JsonPeek

VersionDownloads

Read values from JSON using JSONPath.

Usage:

 <JsonPeekContentPath="[JSON_FILE]"Query="[JSONPath]">
<OutputTaskParameter="Result"PropertyName="Value" />
</JsonPeek>
<JsonPeekContent="[JSON]"Query="[JSONPath]">
<OutputTaskParameter="Result"ItemName="Values" />
</JsonPeek>

Parameters:

ParameterDescription
ContentOptional string parameter.
Specifies the JSON input as a string.
ContentPathOptional ITaskItem parameter.
Specifies the JSON input as a file path.
EmptyOptional string parameter.
Value to use as a replacement for empty values matched in JSON.
QueryRequired string parameter.
Specifies the JSONPath expression.
ResultOutput ITaskItem[] parameter.
Contains the results that are returned by the task.

You can either provide the path to a JSON file via ContentPath or provide the straight JSON content to Content. The Query is a JSONPath expression that is evaluated and returned via the Result task parameter. You can assign the resulting value to either a property (i.e. for a single value) or an item name (i.e. for multiple results).

JSON object properties are automatically projected as item metadata when assigning the resulting value to an item. For example, given the following JSON:

{
"http": {
"host": "localhost",
"port": 80,
"ssl": true
}
}

You can read the entire http value as an item with each property as a metadata value with:

<JsonPeekContentPath="host.json"Query="$.http">
<OutputTaskParameter="Result"ItemName="Http" />
</JsonPeek>

The Http item will have the following values (if it were declared in MSBuild):

<ItemGroup>
<HttpInclude="[item raw json]">
<host>localhost</host>
<port>80</port>
<ssl>true</ssl>
</Http>
</ItemGroup>

These item metadata values could be read as MSBuild properties as follows, for example:

<PropertyGroup>
<Host>@(Http -> '%(host)')</Host>
<Port>@(Http -> '%(port)')</Port>
<Ssl>@(Http -> '%(ssl)')</Ssl>
</PropertyGroup>

In addition to the explicitly opted in object properties, the entire node is available as raw JSON via the special _ (single underscore) metadata item.

If the matched value is empty, no items (because items cannot be constructed with empty identity) or property value will be returned. This makes it difficult to distinguish a successfully matched empty value from no value matched at all. For these cases, it's possible to specify an Empty value to stand-in for an empty (but successful) matched result instead, which allow to distinguish both scenarios:

<JsonPeekContent="$(Json)"Empty="$empty"Query="$(Query)">
<OutputTaskParameter="Result"PropertyName="Value" />
</JsonPeek>
<ErrorCondition="'$(Value)' == '$empty'"Text="The element $(Query) cannot have an empty value." />

JsonPoke Icon JsonPoke

VersionDownloads

Write values to JSON nodes selected with JSONPath

Usage:

 <JsonPokeContentPath="[JSON_FILE]"Query="[JSONPath]"Value="[VALUE]" />
<JsonPokeContentPath="[JSON_FILE]"Query="[JSONPath]"RawValue="[JSON]" />
<JsonPokeContent="[JSON]"Query="[JSONPath]"Value="[VALUE]" />

Parameters:

ParameterDescription
ContentOptional string input/output parameter.
Specifies the JSON input as a string and contains the updated
JSON after successful task execution.
ContentPathOptional ITaskItem parameter.
Specifies the JSON input as a file path.
QueryRequired string parameter.
Specifies the JSONPath expression.
ValueOptional ITaskItem[] parameter.
Specifies the value(s) to be inserted into the specified path.
RawValueOptional string parameter.
Specifies the raw (JSON) value to be inserted into the specified path.

You must either provide the path to a JSON file via ContentPath or raw JSON content via Content.

The Value can be an item group, and in that case, it will be inserted into the JSON node matching the JSONPath expression Query as an array. RawValue can be used to provide an entire JSON fragment as a string, with no conversion to an MSBuild item at all.

The existing JSON node will determine the data type of the value being written, so as to preserve the original document. Numbers, booleans and DateTimes are properly parsed before serializing to the node.

 <PropertyGroup>
<Json>
{
"http": {
"host": "localhost",
"port": 80,
"ssl": true
}
}
</Json>
</PropertyGroup>
<JsonPokeContent="$(Json)"Query="$.http.host"Value="example.com">
<OutputTaskParameter="Content"PropertyName="Json" />
</JsonPoke>
<JsonPokeContent="$(Json)"Query="$.http.port"Value="80">
<OutputTaskParameter="Content"PropertyName="Json" />
</JsonPoke>
<JsonPokeContent="$(Json)"Query="$.http.ssl"Value="true">
<OutputTaskParameter="Content"PropertyName="Json" />
</JsonPoke>
<MessageImportance="high"Text="$(Json)" />

Note how we update multiple values and assign the updated content to the same $(Json) property so it can be used in subsequent updates. The last Message task will render the following JSON:

{
"http": {
"host": "example.com",
"port": 80,
"ssl": true
}
}

NOTE: The port number was preserved as a number, as is the ssl boolean.

To force a value to be interpreted as a string, you can surround it with double or single quotes. For example, given the following JSON file:

{
"http": {
"ports": [
"80"
]
}
}

We can replace the ports array with string values as follows (without the explicit quotes, the values would be interpreted as numbers otherwise):

 <ItemGroup>
<HttpPortInclude="'8080'" />
<HttpPortInclude="'1080'" />
</ItemGroup>
<JsonPokeContentPath="http.json"Query="$.http.ports"Value="@(HttpPort)" />

Result:

{
"http": {
"ports": [
"8080", "1080"
]
}
}

It's also possible to write a complex object based on MSBuild item metadata:

 <ItemGroup>
<HttpInclude="Value">
<host>localhost</host>
<port>80</port>
<ssl>true</ssl>
</Value>
</ItemGroup>
<JsonPokeContentPath="http.json"Query="$.http"Value="@(Http)"Properties="host;port;ssl" />

Result:

{
"http": {
"host": "localhost",
"port": 80,
"ssl": true
}
}

Note how the native JSON type was automatically inferred, even though everything is basically a string in MSBuild. As noted above, you can surround any of the item metadata values in double or single quotes to force them to be written as strings instead.

The task can create entire object hierarchies if any segment of the path expression is not found, which makes it very easy to create complex structures by assigning a single value. For example, if the http section in the examples above didn't exist at all, the following task would add it automatically, prior to assigning the ssl property to true:

<JsonPokeContentPath="http.json"Query="$.http.ssl"Value="true" />

This also works for indexed queries, such as adding launch profile to launchSettings.json by simply assigning a value:

<JsonPokeContentPath="Properties\launchSettings.json"Query="$.profiles['IIS Express'].commandName"Value="IISExpress" />

which would create the following entry:

{
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
}
}
}

Array index is also supported as part of the query, to modify existing values. If the array is empty or non-existent, it's also possible to just use the index [0] to denote the new node should be the sole element in the new array, like for adding a new watch file value to host.json:

<JsonPokeContentPath="host.json"Query="$.watchFiles[0]"Value="myFile.txt" />

Which results in:

{
..."watchFiles": [ "myFile.txt" ]
}

It's quite common to want to add entries to an existing array, usually at the end of the array. The JSONPath syntax supports indexes that start from the end of the array (such as [-1:]), but if the array had any values already, that would match whichever is the last element, meaning in an update to that element's value. Since we need a different syntax for inserting a new node, starting from the end of the list, we leverage the C# syntax ^n where n is the position starting from the end. To add a new element at the end of the list, the index [^1] can be used. ^2 means prior to last and so on.

For example, to add a new watched file to the array in the example above, we could use:

<JsonPokeContentPath="host.json"Query="$.watchFiles[^1]"Value="myOtherFile.txt" />

Given an existing host.json file like the one above, we would get a new file added like so:

{
..."watchFiles": [ "myFile.txt", "myOtherFile.txt" ]
}

If the watchFiles property didn't exit at all or had no elements, the result would be the same as if we used [0], but this makes the code more flexible if needed.

The modified JSON nodes can be assigned to an item name using the Result task property, and will contain the item path (matching the Query plus the index if multiple nodes were modified) as well as the Value item metadata containing the raw JSON that was written.

Dogfooding

CI VersionBuild

We also produce CI packages from branches and pull requests so you can dogfood builds as quickly as they are produced.

The CI feed is https://pkg.kzu.app/index.json.

The versioning scheme for packages is:

  • PR builds: 42.42.42-pr[NUMBER]
  • Branch builds: 42.42.42-[BRANCH].[COMMITS]

Sponsors

Clarius OrgMFB Technologies, Inc.SandRockDRIVE.NET, Inc.Keith PickfordThomas BolonKori FrancisReuben SwartzJacob FosheeEric JohnsonJonathan Ken BonnySimon Croppagileworks-euZheyu ShenVezelChilliCream4OTCdomischellAdrian AlonsotorutekRyan McCafferySeika LogicielAndrew Granteska-gmbhGeodata AS

Sponsor this project

Learn more about GitHub Sponsors

About

JsonPeek and JsonPoke tasks implementations

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

11 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

JSON Icon JsonPeek and JsonPoke MSBuild Tasks

LicenseBuild

JsonPeek Icon JsonPeek

VersionDownloads

Read values from JSON using JSONPath.

Usage:

 <JsonPeekContentPath="[JSON_FILE]"Query="[JSONPath]">
<OutputTaskParameter="Result"PropertyName="Value" />
</JsonPeek>
<JsonPeekContent="[JSON]"Query="[JSONPath]">
<OutputTaskParameter="Result"ItemName="Values" />
</JsonPeek>

Parameters:

ParameterDescription
ContentOptional string parameter.
Specifies the JSON input as a string.
ContentPathOptional ITaskItem parameter.
Specifies the JSON input as a file path.
EmptyOptional string parameter.
Value to use as a replacement for empty values matched in JSON.
QueryRequired string parameter.
Specifies the JSONPath expression.
ResultOutput ITaskItem[] parameter.
Contains the results that are returned by the task.

You can either provide the path to a JSON file via ContentPath or provide the straight JSON content to Content. The Query is a JSONPath expression that is evaluated and returned via the Result task parameter. You can assign the resulting value to either a property (i.e. for a single value) or an item name (i.e. for multiple results).

JSON object properties are automatically projected as item metadata when assigning the resulting value to an item. For example, given the following JSON:

{
"http": {
"host": "localhost",
"port": 80,
"ssl": true
}
}

You can read the entire http value as an item with each property as a metadata value with:

<JsonPeekContentPath="host.json"Query="$.http">
<OutputTaskParameter="Result"ItemName="Http" />
</JsonPeek>

The Http item will have the following values (if it were declared in MSBuild):

<ItemGroup>
<HttpInclude="[item raw json]">
<host>localhost</host>
<port>80</port>
<ssl>true</ssl>
</Http>
</ItemGroup>

These item metadata values could be read as MSBuild properties as follows, for example:

<PropertyGroup>
<Host>@(Http -> '%(host)')</Host>
<Port>@(Http -> '%(port)')</Port>
<Ssl>@(Http -> '%(ssl)')</Ssl>
</PropertyGroup>

In addition to the explicitly opted in object properties, the entire node is available as raw JSON via the special _ (single underscore) metadata item.

If the matched value is empty, no items (because items cannot be constructed with empty identity) or property value will be returned. This makes it difficult to distinguish a successfully matched empty value from no value matched at all. For these cases, it's possible to specify an Empty value to stand-in for an empty (but successful) matched result instead, which allow to distinguish both scenarios:

<JsonPeekContent="$(Json)"Empty="$empty"Query="$(Query)">
<OutputTaskParameter="Result"PropertyName="Value" />
</JsonPeek>
<ErrorCondition="'$(Value)' == '$empty'"Text="The element $(Query) cannot have an empty value." />

JsonPoke Icon JsonPoke

VersionDownloads

Write values to JSON nodes selected with JSONPath

Usage:

 <JsonPokeContentPath="[JSON_FILE]"Query="[JSONPath]"Value="[VALUE]" />
<JsonPokeContentPath="[JSON_FILE]"Query="[JSONPath]"RawValue="[JSON]" />
<JsonPokeContent="[JSON]"Query="[JSONPath]"Value="[VALUE]" />

Parameters:

ParameterDescription
ContentOptional string input/output parameter.
Specifies the JSON input as a string and contains the updated
JSON after successful task execution.
ContentPathOptional ITaskItem parameter.
Specifies the JSON input as a file path.
QueryRequired string parameter.
Specifies the JSONPath expression.
ValueOptional ITaskItem[] parameter.
Specifies the value(s) to be inserted into the specified path.
RawValueOptional string parameter.
Specifies the raw (JSON) value to be inserted into the specified path.

You must either provide the path to a JSON file via ContentPath or raw JSON content via Content.

The Value can be an item group, and in that case, it will be inserted into the JSON node matching the JSONPath expression Query as an array. RawValue can be used to provide an entire JSON fragment as a string, with no conversion to an MSBuild item at all.

The existing JSON node will determine the data type of the value being written, so as to preserve the original document. Numbers, booleans and DateTimes are properly parsed before serializing to the node.

 <PropertyGroup>
<Json>
{
"http": {
"host": "localhost",
"port": 80,
"ssl": true
}
}
</Json>
</PropertyGroup>
<JsonPokeContent="$(Json)"Query="$.http.host"Value="example.com">
<OutputTaskParameter="Content"PropertyName="Json" />
</JsonPoke>
<JsonPokeContent="$(Json)"Query="$.http.port"Value="80">
<OutputTaskParameter="Content"PropertyName="Json" />
</JsonPoke>
<JsonPokeContent="$(Json)"Query="$.http.ssl"Value="true">
<OutputTaskParameter="Content"PropertyName="Json" />
</JsonPoke>
<MessageImportance="high"Text="$(Json)" />

Note how we update multiple values and assign the updated content to the same $(Json) property so it can be used in subsequent updates. The last Message task will render the following JSON:

{
"http": {
"host": "example.com",
"port": 80,
"ssl": true
}
}

NOTE: The port number was preserved as a number, as is the ssl boolean.

To force a value to be interpreted as a string, you can surround it with double or single quotes. For example, given the following JSON file:

{
"http": {
"ports": [
"80"
]
}
}

We can replace the ports array with string values as follows (without the explicit quotes, the values would be interpreted as numbers otherwise):

 <ItemGroup>
<HttpPortInclude="'8080'" />
<HttpPortInclude="'1080'" />
</ItemGroup>
<JsonPokeContentPath="http.json"Query="$.http.ports"Value="@(HttpPort)" />

Result:

{
"http": {
"ports": [
"8080", "1080"
]
}
}

It's also possible to write a complex object based on MSBuild item metadata:

 <ItemGroup>
<HttpInclude="Value">
<host>localhost</host>
<port>80</port>
<ssl>true</ssl>
</Value>
</ItemGroup>
<JsonPokeContentPath="http.json"Query="$.http"Value="@(Http)"Properties="host;port;ssl" />

Result:

{
"http": {
"host": "localhost",
"port": 80,
"ssl": true
}
}

Note how the native JSON type was automatically inferred, even though everything is basically a string in MSBuild. As noted above, you can surround any of the item metadata values in double or single quotes to force them to be written as strings instead.

The task can create entire object hierarchies if any segment of the path expression is not found, which makes it very easy to create complex structures by assigning a single value. For example, if the http section in the examples above didn't exist at all, the following task would add it automatically, prior to assigning the ssl property to true:

<JsonPokeContentPath="http.json"Query="$.http.ssl"Value="true" />

This also works for indexed queries, such as adding launch profile to launchSettings.json by simply assigning a value:

<JsonPokeContentPath="Properties\launchSettings.json"Query="$.profiles['IIS Express'].commandName"Value="IISExpress" />

which would create the following entry:

{
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
}
}
}

Array index is also supported as part of the query, to modify existing values. If the array is empty or non-existent, it's also possible to just use the index [0] to denote the new node should be the sole element in the new array, like for adding a new watch file value to host.json:

<JsonPokeContentPath="host.json"Query="$.watchFiles[0]"Value="myFile.txt" />

Which results in:

{
..."watchFiles": [ "myFile.txt" ]
}

It's quite common to want to add entries to an existing array, usually at the end of the array. The JSONPath syntax supports indexes that start from the end of the array (such as [-1:]), but if the array had any values already, that would match whichever is the last element, meaning in an update to that element's value. Since we need a different syntax for inserting a new node, starting from the end of the list, we leverage the C# syntax ^n where n is the position starting from the end. To add a new element at the end of the list, the index [^1] can be used. ^2 means prior to last and so on.

For example, to add a new watched file to the array in the example above, we could use:

<JsonPokeContentPath="host.json"Query="$.watchFiles[^1]"Value="myOtherFile.txt" />

Given an existing host.json file like the one above, we would get a new file added like so:

{
..."watchFiles": [ "myFile.txt", "myOtherFile.txt" ]
}

If the watchFiles property didn't exit at all or had no elements, the result would be the same as if we used [0], but this makes the code more flexible if needed.

The modified JSON nodes can be assigned to an item name using the Result task property, and will contain the item path (matching the Query plus the index if multiple nodes were modified) as well as the Value item metadata containing the raw JSON that was written.

Dogfooding

CI VersionBuild

We also produce CI packages from branches and pull requests so you can dogfood builds as quickly as they are produced.

The CI feed is https://pkg.kzu.app/index.json.

The versioning scheme for packages is:

  • PR builds: 42.42.42-pr[NUMBER]
  • Branch builds: 42.42.42-[BRANCH].[COMMITS]

Sponsors

Clarius OrgMFB Technologies, Inc.SandRockDRIVE.NET, Inc.Keith PickfordThomas BolonKori FrancisReuben SwartzJacob FosheeEric JohnsonJonathan Ken BonnySimon Croppagileworks-euZheyu ShenVezelChilliCream4OTCdomischellAdrian AlonsotorutekRyan McCafferySeika LogicielAndrew Granteska-gmbhGeodata AS

Sponsor this project

Learn more about GitHub Sponsors

About

JsonPeek and JsonPoke tasks implementations

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

11 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

JSON Icon JsonPeek and JsonPoke MSBuild Tasks

LicenseBuild

JsonPeek Icon JsonPeek

VersionDownloads

Read values from JSON using JSONPath.

Usage:

 <JsonPeekContentPath="[JSON_FILE]"Query="[JSONPath]">
<OutputTaskParameter="Result"PropertyName="Value" />
</JsonPeek>
<JsonPeekContent="[JSON]"Query="[JSONPath]">
<OutputTaskParameter="Result"ItemName="Values" />
</JsonPeek>

Parameters:

ParameterDescription
ContentOptional string parameter.
Specifies the JSON input as a string.
ContentPathOptional ITaskItem parameter.
Specifies the JSON input as a file path.
EmptyOptional string parameter.
Value to use as a replacement for empty values matched in JSON.
QueryRequired string parameter.
Specifies the JSONPath expression.
ResultOutput ITaskItem[] parameter.
Contains the results that are returned by the task.

You can either provide the path to a JSON file via ContentPath or provide the straight JSON content to Content. The Query is a JSONPath expression that is evaluated and returned via the Result task parameter. You can assign the resulting value to either a property (i.e. for a single value) or an item name (i.e. for multiple results).

JSON object properties are automatically projected as item metadata when assigning the resulting value to an item. For example, given the following JSON:

{
"http": {
"host": "localhost",
"port": 80,
"ssl": true
}
}

You can read the entire http value as an item with each property as a metadata value with:

<JsonPeekContentPath="host.json"Query="$.http">
<OutputTaskParameter="Result"ItemName="Http" />
</JsonPeek>

The Http item will have the following values (if it were declared in MSBuild):

<ItemGroup>
<HttpInclude="[item raw json]">
<host>localhost</host>
<port>80</port>
<ssl>true</ssl>
</Http>
</ItemGroup>

These item metadata values could be read as MSBuild properties as follows, for example:

<PropertyGroup>
<Host>@(Http -> '%(host)')</Host>
<Port>@(Http -> '%(port)')</Port>
<Ssl>@(Http -> '%(ssl)')</Ssl>
</PropertyGroup>

In addition to the explicitly opted in object properties, the entire node is available as raw JSON via the special _ (single underscore) metadata item.

If the matched value is empty, no items (because items cannot be constructed with empty identity) or property value will be returned. This makes it difficult to distinguish a successfully matched empty value from no value matched at all. For these cases, it's possible to specify an Empty value to stand-in for an empty (but successful) matched result instead, which allow to distinguish both scenarios:

<JsonPeekContent="$(Json)"Empty="$empty"Query="$(Query)">
<OutputTaskParameter="Result"PropertyName="Value" />
</JsonPeek>
<ErrorCondition="'$(Value)' == '$empty'"Text="The element $(Query) cannot have an empty value." />

JsonPoke Icon JsonPoke

VersionDownloads

Write values to JSON nodes selected with JSONPath

Usage:

 <JsonPokeContentPath="[JSON_FILE]"Query="[JSONPath]"Value="[VALUE]" />
<JsonPokeContentPath="[JSON_FILE]"Query="[JSONPath]"RawValue="[JSON]" />
<JsonPokeContent="[JSON]"Query="[JSONPath]"Value="[VALUE]" />

Parameters:

ParameterDescription
ContentOptional string input/output parameter.
Specifies the JSON input as a string and contains the updated
JSON after successful task execution.
ContentPathOptional ITaskItem parameter.
Specifies the JSON input as a file path.
QueryRequired string parameter.
Specifies the JSONPath expression.
ValueOptional ITaskItem[] parameter.
Specifies the value(s) to be inserted into the specified path.
RawValueOptional string parameter.
Specifies the raw (JSON) value to be inserted into the specified path.

You must either provide the path to a JSON file via ContentPath or raw JSON content via Content.

The Value can be an item group, and in that case, it will be inserted into the JSON node matching the JSONPath expression Query as an array. RawValue can be used to provide an entire JSON fragment as a string, with no conversion to an MSBuild item at all.

The existing JSON node will determine the data type of the value being written, so as to preserve the original document. Numbers, booleans and DateTimes are properly parsed before serializing to the node.

 <PropertyGroup>
<Json>
{
"http": {
"host": "localhost",
"port": 80,
"ssl": true
}
}
</Json>
</PropertyGroup>
<JsonPokeContent="$(Json)"Query="$.http.host"Value="example.com">
<OutputTaskParameter="Content"PropertyName="Json" />
</JsonPoke>
<JsonPokeContent="$(Json)"Query="$.http.port"Value="80">
<OutputTaskParameter="Content"PropertyName="Json" />
</JsonPoke>
<JsonPokeContent="$(Json)"Query="$.http.ssl"Value="true">
<OutputTaskParameter="Content"PropertyName="Json" />
</JsonPoke>
<MessageImportance="high"Text="$(Json)" />

Note how we update multiple values and assign the updated content to the same $(Json) property so it can be used in subsequent updates. The last Message task will render the following JSON:

{
"http": {
"host": "example.com",
"port": 80,
"ssl": true
}
}

NOTE: The port number was preserved as a number, as is the ssl boolean.

To force a value to be interpreted as a string, you can surround it with double or single quotes. For example, given the following JSON file:

{
"http": {
"ports": [
"80"
]
}
}

We can replace the ports array with string values as follows (without the explicit quotes, the values would be interpreted as numbers otherwise):

 <ItemGroup>
<HttpPortInclude="'8080'" />
<HttpPortInclude="'1080'" />
</ItemGroup>
<JsonPokeContentPath="http.json"Query="$.http.ports"Value="@(HttpPort)" />

Result:

{
"http": {
"ports": [
"8080", "1080"
]
}
}

It's also possible to write a complex object based on MSBuild item metadata:

 <ItemGroup>
<HttpInclude="Value">
<host>localhost</host>
<port>80</port>
<ssl>true</ssl>
</Value>
</ItemGroup>
<JsonPokeContentPath="http.json"Query="$.http"Value="@(Http)"Properties="host;port;ssl" />

Result:

{
"http": {
"host": "localhost",
"port": 80,
"ssl": true
}
}

Note how the native JSON type was automatically inferred, even though everything is basically a string in MSBuild. As noted above, you can surround any of the item metadata values in double or single quotes to force them to be written as strings instead.

The task can create entire object hierarchies if any segment of the path expression is not found, which makes it very easy to create complex structures by assigning a single value. For example, if the http section in the examples above didn't exist at all, the following task would add it automatically, prior to assigning the ssl property to true:

<JsonPokeContentPath="http.json"Query="$.http.ssl"Value="true" />

This also works for indexed queries, such as adding launch profile to launchSettings.json by simply assigning a value:

<JsonPokeContentPath="Properties\launchSettings.json"Query="$.profiles['IIS Express'].commandName"Value="IISExpress" />

which would create the following entry:

{
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
}
}
}

Array index is also supported as part of the query, to modify existing values. If the array is empty or non-existent, it's also possible to just use the index [0] to denote the new node should be the sole element in the new array, like for adding a new watch file value to host.json:

<JsonPokeContentPath="host.json"Query="$.watchFiles[0]"Value="myFile.txt" />

Which results in:

{
..."watchFiles": [ "myFile.txt" ]
}

It's quite common to want to add entries to an existing array, usually at the end of the array. The JSONPath syntax supports indexes that start from the end of the array (such as [-1:]), but if the array had any values already, that would match whichever is the last element, meaning in an update to that element's value. Since we need a different syntax for inserting a new node, starting from the end of the list, we leverage the C# syntax ^n where n is the position starting from the end. To add a new element at the end of the list, the index [^1] can be used. ^2 means prior to last and so on.

For example, to add a new watched file to the array in the example above, we could use:

<JsonPokeContentPath="host.json"Query="$.watchFiles[^1]"Value="myOtherFile.txt" />

Given an existing host.json file like the one above, we would get a new file added like so:

{
..."watchFiles": [ "myFile.txt", "myOtherFile.txt" ]
}

If the watchFiles property didn't exit at all or had no elements, the result would be the same as if we used [0], but this makes the code more flexible if needed.

The modified JSON nodes can be assigned to an item name using the Result task property, and will contain the item path (matching the Query plus the index if multiple nodes were modified) as well as the Value item metadata containing the raw JSON that was written.

Dogfooding

CI VersionBuild

We also produce CI packages from branches and pull requests so you can dogfood builds as quickly as they are produced.

The CI feed is https://pkg.kzu.app/index.json.

The versioning scheme for packages is:

  • PR builds: 42.42.42-pr[NUMBER]
  • Branch builds: 42.42.42-[BRANCH].[COMMITS]

Sponsors

Clarius OrgMFB Technologies, Inc.SandRockDRIVE.NET, Inc.Keith PickfordThomas BolonKori FrancisReuben SwartzJacob FosheeEric JohnsonJonathan Ken BonnySimon Croppagileworks-euZheyu ShenVezelChilliCream4OTCdomischellAdrian AlonsotorutekRyan McCafferySeika LogicielAndrew Granteska-gmbhGeodata AS

Sponsor this project

Learn more about GitHub Sponsors

About

JsonPeek and JsonPoke tasks implementations

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

11 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

JSON Icon JsonPeek and JsonPoke MSBuild Tasks

LicenseBuild

JsonPeek Icon JsonPeek

VersionDownloads

Read values from JSON using JSONPath.

Usage:

 <JsonPeekContentPath="[JSON_FILE]"Query="[JSONPath]">
<OutputTaskParameter="Result"PropertyName="Value" />
</JsonPeek>
<JsonPeekContent="[JSON]"Query="[JSONPath]">
<OutputTaskParameter="Result"ItemName="Values" />
</JsonPeek>

Parameters:

ParameterDescription
ContentOptional string parameter.
Specifies the JSON input as a string.
ContentPathOptional ITaskItem parameter.
Specifies the JSON input as a file path.
EmptyOptional string parameter.
Value to use as a replacement for empty values matched in JSON.
QueryRequired string parameter.
Specifies the JSONPath expression.
ResultOutput ITaskItem[] parameter.
Contains the results that are returned by the task.

You can either provide the path to a JSON file via ContentPath or provide the straight JSON content to Content. The Query is a JSONPath expression that is evaluated and returned via the Result task parameter. You can assign the resulting value to either a property (i.e. for a single value) or an item name (i.e. for multiple results).

JSON object properties are automatically projected as item metadata when assigning the resulting value to an item. For example, given the following JSON:

{
"http": {
"host": "localhost",
"port": 80,
"ssl": true
}
}

You can read the entire http value as an item with each property as a metadata value with:

<JsonPeekContentPath="host.json"Query="$.http">
<OutputTaskParameter="Result"ItemName="Http" />
</JsonPeek>

The Http item will have the following values (if it were declared in MSBuild):

<ItemGroup>
<HttpInclude="[item raw json]">
<host>localhost</host>
<port>80</port>
<ssl>true</ssl>
</Http>
</ItemGroup>

These item metadata values could be read as MSBuild properties as follows, for example:

<PropertyGroup>
<Host>@(Http -> '%(host)')</Host>
<Port>@(Http -> '%(port)')</Port>
<Ssl>@(Http -> '%(ssl)')</Ssl>
</PropertyGroup>

In addition to the explicitly opted in object properties, the entire node is available as raw JSON via the special _ (single underscore) metadata item.

If the matched value is empty, no items (because items cannot be constructed with empty identity) or property value will be returned. This makes it difficult to distinguish a successfully matched empty value from no value matched at all. For these cases, it's possible to specify an Empty value to stand-in for an empty (but successful) matched result instead, which allow to distinguish both scenarios:

<JsonPeekContent="$(Json)"Empty="$empty"Query="$(Query)">
<OutputTaskParameter="Result"PropertyName="Value" />
</JsonPeek>
<ErrorCondition="'$(Value)' == '$empty'"Text="The element $(Query) cannot have an empty value." />

JsonPoke Icon JsonPoke

VersionDownloads

Write values to JSON nodes selected with JSONPath

Usage:

 <JsonPokeContentPath="[JSON_FILE]"Query="[JSONPath]"Value="[VALUE]" />
<JsonPokeContentPath="[JSON_FILE]"Query="[JSONPath]"RawValue="[JSON]" />
<JsonPokeContent="[JSON]"Query="[JSONPath]"Value="[VALUE]" />

Parameters:

ParameterDescription
ContentOptional string input/output parameter.
Specifies the JSON input as a string and contains the updated
JSON after successful task execution.
ContentPathOptional ITaskItem parameter.
Specifies the JSON input as a file path.
QueryRequired string parameter.
Specifies the JSONPath expression.
ValueOptional ITaskItem[] parameter.
Specifies the value(s) to be inserted into the specified path.
RawValueOptional string parameter.
Specifies the raw (JSON) value to be inserted into the specified path.

You must either provide the path to a JSON file via ContentPath or raw JSON content via Content.

The Value can be an item group, and in that case, it will be inserted into the JSON node matching the JSONPath expression Query as an array. RawValue can be used to provide an entire JSON fragment as a string, with no conversion to an MSBuild item at all.

The existing JSON node will determine the data type of the value being written, so as to preserve the original document. Numbers, booleans and DateTimes are properly parsed before serializing to the node.

 <PropertyGroup>
<Json>
{
"http": {
"host": "localhost",
"port": 80,
"ssl": true
}
}
</Json>
</PropertyGroup>
<JsonPokeContent="$(Json)"Query="$.http.host"Value="example.com">
<OutputTaskParameter="Content"PropertyName="Json" />
</JsonPoke>
<JsonPokeContent="$(Json)"Query="$.http.port"Value="80">
<OutputTaskParameter="Content"PropertyName="Json" />
</JsonPoke>
<JsonPokeContent="$(Json)"Query="$.http.ssl"Value="true">
<OutputTaskParameter="Content"PropertyName="Json" />
</JsonPoke>
<MessageImportance="high"Text="$(Json)" />

Note how we update multiple values and assign the updated content to the same $(Json) property so it can be used in subsequent updates. The last Message task will render the following JSON:

{
"http": {
"host": "example.com",
"port": 80,
"ssl": true
}
}

NOTE: The port number was preserved as a number, as is the ssl boolean.

To force a value to be interpreted as a string, you can surround it with double or single quotes. For example, given the following JSON file:

{
"http": {
"ports": [
"80"
]
}
}

We can replace the ports array with string values as follows (without the explicit quotes, the values would be interpreted as numbers otherwise):

 <ItemGroup>
<HttpPortInclude="'8080'" />
<HttpPortInclude="'1080'" />
</ItemGroup>
<JsonPokeContentPath="http.json"Query="$.http.ports"Value="@(HttpPort)" />

Result:

{
"http": {
"ports": [
"8080", "1080"
]
}
}

It's also possible to write a complex object based on MSBuild item metadata:

 <ItemGroup>
<HttpInclude="Value">
<host>localhost</host>
<port>80</port>
<ssl>true</ssl>
</Value>
</ItemGroup>
<JsonPokeContentPath="http.json"Query="$.http"Value="@(Http)"Properties="host;port;ssl" />

Result:

{
"http": {
"host": "localhost",
"port": 80,
"ssl": true
}
}

Note how the native JSON type was automatically inferred, even though everything is basically a string in MSBuild. As noted above, you can surround any of the item metadata values in double or single quotes to force them to be written as strings instead.

The task can create entire object hierarchies if any segment of the path expression is not found, which makes it very easy to create complex structures by assigning a single value. For example, if the http section in the examples above didn't exist at all, the following task would add it automatically, prior to assigning the ssl property to true:

<JsonPokeContentPath="http.json"Query="$.http.ssl"Value="true" />

This also works for indexed queries, such as adding launch profile to launchSettings.json by simply assigning a value:

<JsonPokeContentPath="Properties\launchSettings.json"Query="$.profiles['IIS Express'].commandName"Value="IISExpress" />

which would create the following entry:

{
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
}
}
}

Array index is also supported as part of the query, to modify existing values. If the array is empty or non-existent, it's also possible to just use the index [0] to denote the new node should be the sole element in the new array, like for adding a new watch file value to host.json:

<JsonPokeContentPath="host.json"Query="$.watchFiles[0]"Value="myFile.txt" />

Which results in:

{
..."watchFiles": [ "myFile.txt" ]
}

It's quite common to want to add entries to an existing array, usually at the end of the array. The JSONPath syntax supports indexes that start from the end of the array (such as [-1:]), but if the array had any values already, that would match whichever is the last element, meaning in an update to that element's value. Since we need a different syntax for inserting a new node, starting from the end of the list, we leverage the C# syntax ^n where n is the position starting from the end. To add a new element at the end of the list, the index [^1] can be used. ^2 means prior to last and so on.

For example, to add a new watched file to the array in the example above, we could use:

<JsonPokeContentPath="host.json"Query="$.watchFiles[^1]"Value="myOtherFile.txt" />

Given an existing host.json file like the one above, we would get a new file added like so:

{
..."watchFiles": [ "myFile.txt", "myOtherFile.txt" ]
}

If the watchFiles property didn't exit at all or had no elements, the result would be the same as if we used [0], but this makes the code more flexible if needed.

The modified JSON nodes can be assigned to an item name using the Result task property, and will contain the item path (matching the Query plus the index if multiple nodes were modified) as well as the Value item metadata containing the raw JSON that was written.

Dogfooding

CI VersionBuild

We also produce CI packages from branches and pull requests so you can dogfood builds as quickly as they are produced.

The CI feed is https://pkg.kzu.app/index.json.

The versioning scheme for packages is:

  • PR builds: 42.42.42-pr[NUMBER]
  • Branch builds: 42.42.42-[BRANCH].[COMMITS]

Sponsors

Clarius OrgMFB Technologies, Inc.SandRockDRIVE.NET, Inc.Keith PickfordThomas BolonKori FrancisReuben SwartzJacob FosheeEric JohnsonJonathan Ken BonnySimon Croppagileworks-euZheyu ShenVezelChilliCream4OTCdomischellAdrian AlonsotorutekRyan McCafferySeika LogicielAndrew Granteska-gmbhGeodata AS

Sponsor this project

Learn more about GitHub Sponsors

About

JsonPeek and JsonPoke tasks implementations

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

11 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

JSON Icon JsonPeek and JsonPoke MSBuild Tasks

LicenseBuild

JsonPeek Icon JsonPeek

VersionDownloads

Read values from JSON using JSONPath.

Usage:

 <JsonPeekContentPath="[JSON_FILE]"Query="[JSONPath]">
<OutputTaskParameter="Result"PropertyName="Value" />
</JsonPeek>
<JsonPeekContent="[JSON]"Query="[JSONPath]">
<OutputTaskParameter="Result"ItemName="Values" />
</JsonPeek>

Parameters:

ParameterDescription
ContentOptional string parameter.
Specifies the JSON input as a string.
ContentPathOptional ITaskItem parameter.
Specifies the JSON input as a file path.
EmptyOptional string parameter.
Value to use as a replacement for empty values matched in JSON.
QueryRequired string parameter.
Specifies the JSONPath expression.
ResultOutput ITaskItem[] parameter.
Contains the results that are returned by the task.

You can either provide the path to a JSON file via ContentPath or provide the straight JSON content to Content. The Query is a JSONPath expression that is evaluated and returned via the Result task parameter. You can assign the resulting value to either a property (i.e. for a single value) or an item name (i.e. for multiple results).

JSON object properties are automatically projected as item metadata when assigning the resulting value to an item. For example, given the following JSON:

{
"http": {
"host": "localhost",
"port": 80,
"ssl": true
}
}

You can read the entire http value as an item with each property as a metadata value with:

<JsonPeekContentPath="host.json"Query="$.http">
<OutputTaskParameter="Result"ItemName="Http" />
</JsonPeek>

The Http item will have the following values (if it were declared in MSBuild):

<ItemGroup>
<HttpInclude="[item raw json]">
<host>localhost</host>
<port>80</port>
<ssl>true</ssl>
</Http>
</ItemGroup>

These item metadata values could be read as MSBuild properties as follows, for example:

<PropertyGroup>
<Host>@(Http -> '%(host)')</Host>
<Port>@(Http -> '%(port)')</Port>
<Ssl>@(Http -> '%(ssl)')</Ssl>
</PropertyGroup>

In addition to the explicitly opted in object properties, the entire node is available as raw JSON via the special _ (single underscore) metadata item.

If the matched value is empty, no items (because items cannot be constructed with empty identity) or property value will be returned. This makes it difficult to distinguish a successfully matched empty value from no value matched at all. For these cases, it's possible to specify an Empty value to stand-in for an empty (but successful) matched result instead, which allow to distinguish both scenarios:

<JsonPeekContent="$(Json)"Empty="$empty"Query="$(Query)">
<OutputTaskParameter="Result"PropertyName="Value" />
</JsonPeek>
<ErrorCondition="'$(Value)' == '$empty'"Text="The element $(Query) cannot have an empty value." />

JsonPoke Icon JsonPoke

VersionDownloads

Write values to JSON nodes selected with JSONPath

Usage:

 <JsonPokeContentPath="[JSON_FILE]"Query="[JSONPath]"Value="[VALUE]" />
<JsonPokeContentPath="[JSON_FILE]"Query="[JSONPath]"RawValue="[JSON]" />
<JsonPokeContent="[JSON]"Query="[JSONPath]"Value="[VALUE]" />

Parameters:

ParameterDescription
ContentOptional string input/output parameter.
Specifies the JSON input as a string and contains the updated
JSON after successful task execution.
ContentPathOptional ITaskItem parameter.
Specifies the JSON input as a file path.
QueryRequired string parameter.
Specifies the JSONPath expression.
ValueOptional ITaskItem[] parameter.
Specifies the value(s) to be inserted into the specified path.
RawValueOptional string parameter.
Specifies the raw (JSON) value to be inserted into the specified path.

You must either provide the path to a JSON file via ContentPath or raw JSON content via Content.

The Value can be an item group, and in that case, it will be inserted into the JSON node matching the JSONPath expression Query as an array. RawValue can be used to provide an entire JSON fragment as a string, with no conversion to an MSBuild item at all.

The existing JSON node will determine the data type of the value being written, so as to preserve the original document. Numbers, booleans and DateTimes are properly parsed before serializing to the node.

 <PropertyGroup>
<Json>
{
"http": {
"host": "localhost",
"port": 80,
"ssl": true
}
}
</Json>
</PropertyGroup>
<JsonPokeContent="$(Json)"Query="$.http.host"Value="example.com">
<OutputTaskParameter="Content"PropertyName="Json" />
</JsonPoke>
<JsonPokeContent="$(Json)"Query="$.http.port"Value="80">
<OutputTaskParameter="Content"PropertyName="Json" />
</JsonPoke>
<JsonPokeContent="$(Json)"Query="$.http.ssl"Value="true">
<OutputTaskParameter="Content"PropertyName="Json" />
</JsonPoke>
<MessageImportance="high"Text="$(Json)" />

Note how we update multiple values and assign the updated content to the same $(Json) property so it can be used in subsequent updates. The last Message task will render the following JSON:

{
"http": {
"host": "example.com",
"port": 80,
"ssl": true
}
}

NOTE: The port number was preserved as a number, as is the ssl boolean.

To force a value to be interpreted as a string, you can surround it with double or single quotes. For example, given the following JSON file:

{
"http": {
"ports": [
"80"
]
}
}

We can replace the ports array with string values as follows (without the explicit quotes, the values would be interpreted as numbers otherwise):

 <ItemGroup>
<HttpPortInclude="'8080'" />
<HttpPortInclude="'1080'" />
</ItemGroup>
<JsonPokeContentPath="http.json"Query="$.http.ports"Value="@(HttpPort)" />

Result:

{
"http": {
"ports": [
"8080", "1080"
]
}
}

It's also possible to write a complex object based on MSBuild item metadata:

 <ItemGroup>
<HttpInclude="Value">
<host>localhost</host>
<port>80</port>
<ssl>true</ssl>
</Value>
</ItemGroup>
<JsonPokeContentPath="http.json"Query="$.http"Value="@(Http)"Properties="host;port;ssl" />

Result:

{
"http": {
"host": "localhost",
"port": 80,
"ssl": true
}
}

Note how the native JSON type was automatically inferred, even though everything is basically a string in MSBuild. As noted above, you can surround any of the item metadata values in double or single quotes to force them to be written as strings instead.

The task can create entire object hierarchies if any segment of the path expression is not found, which makes it very easy to create complex structures by assigning a single value. For example, if the http section in the examples above didn't exist at all, the following task would add it automatically, prior to assigning the ssl property to true:

<JsonPokeContentPath="http.json"Query="$.http.ssl"Value="true" />

This also works for indexed queries, such as adding launch profile to launchSettings.json by simply assigning a value:

<JsonPokeContentPath="Properties\launchSettings.json"Query="$.profiles['IIS Express'].commandName"Value="IISExpress" />

which would create the following entry:

{
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
}
}
}

Array index is also supported as part of the query, to modify existing values. If the array is empty or non-existent, it's also possible to just use the index [0] to denote the new node should be the sole element in the new array, like for adding a new watch file value to host.json:

<JsonPokeContentPath="host.json"Query="$.watchFiles[0]"Value="myFile.txt" />

Which results in:

{
..."watchFiles": [ "myFile.txt" ]
}

It's quite common to want to add entries to an existing array, usually at the end of the array. The JSONPath syntax supports indexes that start from the end of the array (such as [-1:]), but if the array had any values already, that would match whichever is the last element, meaning in an update to that element's value. Since we need a different syntax for inserting a new node, starting from the end of the list, we leverage the C# syntax ^n where n is the position starting from the end. To add a new element at the end of the list, the index [^1] can be used. ^2 means prior to last and so on.

For example, to add a new watched file to the array in the example above, we could use:

<JsonPokeContentPath="host.json"Query="$.watchFiles[^1]"Value="myOtherFile.txt" />

Given an existing host.json file like the one above, we would get a new file added like so:

{
..."watchFiles": [ "myFile.txt", "myOtherFile.txt" ]
}

If the watchFiles property didn't exit at all or had no elements, the result would be the same as if we used [0], but this makes the code more flexible if needed.

The modified JSON nodes can be assigned to an item name using the Result task property, and will contain the item path (matching the Query plus the index if multiple nodes were modified) as well as the Value item metadata containing the raw JSON that was written.

Dogfooding

CI VersionBuild

We also produce CI packages from branches and pull requests so you can dogfood builds as quickly as they are produced.

The CI feed is https://pkg.kzu.app/index.json.

The versioning scheme for packages is:

  • PR builds: 42.42.42-pr[NUMBER]
  • Branch builds: 42.42.42-[BRANCH].[COMMITS]

Sponsors

Clarius OrgMFB Technologies, Inc.SandRockDRIVE.NET, Inc.Keith PickfordThomas BolonKori FrancisReuben SwartzJacob FosheeEric JohnsonJonathan Ken BonnySimon Croppagileworks-euZheyu ShenVezelChilliCream4OTCdomischellAdrian AlonsotorutekRyan McCafferySeika LogicielAndrew Granteska-gmbhGeodata AS

Sponsor this project

Learn more about GitHub Sponsors

About

JsonPeek and JsonPoke tasks implementations

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

11 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

JSON Icon JsonPeek and JsonPoke MSBuild Tasks

LicenseBuild

JsonPeek Icon JsonPeek

VersionDownloads

Read values from JSON using JSONPath.

Usage:

 <JsonPeekContentPath="[JSON_FILE]"Query="[JSONPath]">
<OutputTaskParameter="Result"PropertyName="Value" />
</JsonPeek>
<JsonPeekContent="[JSON]"Query="[JSONPath]">
<OutputTaskParameter="Result"ItemName="Values" />
</JsonPeek>

Parameters:

ParameterDescription
ContentOptional string parameter.
Specifies the JSON input as a string.
ContentPathOptional ITaskItem parameter.
Specifies the JSON input as a file path.
EmptyOptional string parameter.
Value to use as a replacement for empty values matched in JSON.
QueryRequired string parameter.
Specifies the JSONPath expression.
ResultOutput ITaskItem[] parameter.
Contains the results that are returned by the task.

You can either provide the path to a JSON file via ContentPath or provide the straight JSON content to Content. The Query is a JSONPath expression that is evaluated and returned via the Result task parameter. You can assign the resulting value to either a property (i.e. for a single value) or an item name (i.e. for multiple results).

JSON object properties are automatically projected as item metadata when assigning the resulting value to an item. For example, given the following JSON:

{
"http": {
"host": "localhost",
"port": 80,
"ssl": true
}
}

You can read the entire http value as an item with each property as a metadata value with:

<JsonPeekContentPath="host.json"Query="$.http">
<OutputTaskParameter="Result"ItemName="Http" />
</JsonPeek>

The Http item will have the following values (if it were declared in MSBuild):

<ItemGroup>
<HttpInclude="[item raw json]">
<host>localhost</host>
<port>80</port>
<ssl>true</ssl>
</Http>
</ItemGroup>

These item metadata values could be read as MSBuild properties as follows, for example:

<PropertyGroup>
<Host>@(Http -> '%(host)')</Host>
<Port>@(Http -> '%(port)')</Port>
<Ssl>@(Http -> '%(ssl)')</Ssl>
</PropertyGroup>

In addition to the explicitly opted in object properties, the entire node is available as raw JSON via the special _ (single underscore) metadata item.

If the matched value is empty, no items (because items cannot be constructed with empty identity) or property value will be returned. This makes it difficult to distinguish a successfully matched empty value from no value matched at all. For these cases, it's possible to specify an Empty value to stand-in for an empty (but successful) matched result instead, which allow to distinguish both scenarios:

<JsonPeekContent="$(Json)"Empty="$empty"Query="$(Query)">
<OutputTaskParameter="Result"PropertyName="Value" />
</JsonPeek>
<ErrorCondition="'$(Value)' == '$empty'"Text="The element $(Query) cannot have an empty value." />

JsonPoke Icon JsonPoke

VersionDownloads

Write values to JSON nodes selected with JSONPath

Usage:

 <JsonPokeContentPath="[JSON_FILE]"Query="[JSONPath]"Value="[VALUE]" />
<JsonPokeContentPath="[JSON_FILE]"Query="[JSONPath]"RawValue="[JSON]" />
<JsonPokeContent="[JSON]"Query="[JSONPath]"Value="[VALUE]" />

Parameters:

ParameterDescription
ContentOptional string input/output parameter.
Specifies the JSON input as a string and contains the updated
JSON after successful task execution.
ContentPathOptional ITaskItem parameter.
Specifies the JSON input as a file path.
QueryRequired string parameter.
Specifies the JSONPath expression.
ValueOptional ITaskItem[] parameter.
Specifies the value(s) to be inserted into the specified path.
RawValueOptional string parameter.
Specifies the raw (JSON) value to be inserted into the specified path.

You must either provide the path to a JSON file via ContentPath or raw JSON content via Content.

The Value can be an item group, and in that case, it will be inserted into the JSON node matching the JSONPath expression Query as an array. RawValue can be used to provide an entire JSON fragment as a string, with no conversion to an MSBuild item at all.

The existing JSON node will determine the data type of the value being written, so as to preserve the original document. Numbers, booleans and DateTimes are properly parsed before serializing to the node.

 <PropertyGroup>
<Json>
{
"http": {
"host": "localhost",
"port": 80,
"ssl": true
}
}
</Json>
</PropertyGroup>
<JsonPokeContent="$(Json)"Query="$.http.host"Value="example.com">
<OutputTaskParameter="Content"PropertyName="Json" />
</JsonPoke>
<JsonPokeContent="$(Json)"Query="$.http.port"Value="80">
<OutputTaskParameter="Content"PropertyName="Json" />
</JsonPoke>
<JsonPokeContent="$(Json)"Query="$.http.ssl"Value="true">
<OutputTaskParameter="Content"PropertyName="Json" />
</JsonPoke>
<MessageImportance="high"Text="$(Json)" />

Note how we update multiple values and assign the updated content to the same $(Json) property so it can be used in subsequent updates. The last Message task will render the following JSON:

{
"http": {
"host": "example.com",
"port": 80,
"ssl": true
}
}

NOTE: The port number was preserved as a number, as is the ssl boolean.

To force a value to be interpreted as a string, you can surround it with double or single quotes. For example, given the following JSON file:

{
"http": {
"ports": [
"80"
]
}
}

We can replace the ports array with string values as follows (without the explicit quotes, the values would be interpreted as numbers otherwise):

 <ItemGroup>
<HttpPortInclude="'8080'" />
<HttpPortInclude="'1080'" />
</ItemGroup>
<JsonPokeContentPath="http.json"Query="$.http.ports"Value="@(HttpPort)" />

Result:

{
"http": {
"ports": [
"8080", "1080"
]
}
}

It's also possible to write a complex object based on MSBuild item metadata:

 <ItemGroup>
<HttpInclude="Value">
<host>localhost</host>
<port>80</port>
<ssl>true</ssl>
</Value>
</ItemGroup>
<JsonPokeContentPath="http.json"Query="$.http"Value="@(Http)"Properties="host;port;ssl" />

Result:

{
"http": {
"host": "localhost",
"port": 80,
"ssl": true
}
}

Note how the native JSON type was automatically inferred, even though everything is basically a string in MSBuild. As noted above, you can surround any of the item metadata values in double or single quotes to force them to be written as strings instead.

The task can create entire object hierarchies if any segment of the path expression is not found, which makes it very easy to create complex structures by assigning a single value. For example, if the http section in the examples above didn't exist at all, the following task would add it automatically, prior to assigning the ssl property to true:

<JsonPokeContentPath="http.json"Query="$.http.ssl"Value="true" />

This also works for indexed queries, such as adding launch profile to launchSettings.json by simply assigning a value:

<JsonPokeContentPath="Properties\launchSettings.json"Query="$.profiles['IIS Express'].commandName"Value="IISExpress" />

which would create the following entry:

{
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
}
}
}

Array index is also supported as part of the query, to modify existing values. If the array is empty or non-existent, it's also possible to just use the index [0] to denote the new node should be the sole element in the new array, like for adding a new watch file value to host.json:

<JsonPokeContentPath="host.json"Query="$.watchFiles[0]"Value="myFile.txt" />

Which results in:

{
..."watchFiles": [ "myFile.txt" ]
}

It's quite common to want to add entries to an existing array, usually at the end of the array. The JSONPath syntax supports indexes that start from the end of the array (such as [-1:]), but if the array had any values already, that would match whichever is the last element, meaning in an update to that element's value. Since we need a different syntax for inserting a new node, starting from the end of the list, we leverage the C# syntax ^n where n is the position starting from the end. To add a new element at the end of the list, the index [^1] can be used. ^2 means prior to last and so on.

For example, to add a new watched file to the array in the example above, we could use:

<JsonPokeContentPath="host.json"Query="$.watchFiles[^1]"Value="myOtherFile.txt" />

Given an existing host.json file like the one above, we would get a new file added like so:

{
..."watchFiles": [ "myFile.txt", "myOtherFile.txt" ]
}

If the watchFiles property didn't exit at all or had no elements, the result would be the same as if we used [0], but this makes the code more flexible if needed.

The modified JSON nodes can be assigned to an item name using the Result task property, and will contain the item path (matching the Query plus the index if multiple nodes were modified) as well as the Value item metadata containing the raw JSON that was written.

Dogfooding

CI VersionBuild

We also produce CI packages from branches and pull requests so you can dogfood builds as quickly as they are produced.

The CI feed is https://pkg.kzu.app/index.json.

The versioning scheme for packages is:

  • PR builds: 42.42.42-pr[NUMBER]
  • Branch builds: 42.42.42-[BRANCH].[COMMITS]

Sponsors

Clarius OrgMFB Technologies, Inc.SandRockDRIVE.NET, Inc.Keith PickfordThomas BolonKori FrancisReuben SwartzJacob FosheeEric JohnsonJonathan Ken BonnySimon Croppagileworks-euZheyu ShenVezelChilliCream4OTCdomischellAdrian AlonsotorutekRyan McCafferySeika LogicielAndrew Granteska-gmbhGeodata AS

Sponsor this project

Learn more about GitHub Sponsors

About

JsonPeek and JsonPoke tasks implementations

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

11 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Used by

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

JSON Icon JsonPeek and JsonPoke MSBuild Tasks

LicenseBuild

JsonPeek Icon JsonPeek

VersionDownloads

Read values from JSON using JSONPath.

Usage:

 <JsonPeekContentPath="[JSON_FILE]"Query="[JSONPath]">
<OutputTaskParameter="Result"PropertyName="Value" />
</JsonPeek>
<JsonPeekContent="[JSON]"Query="[JSONPath]">
<OutputTaskParameter="Result"ItemName="Values" />
</JsonPeek>

Parameters:

ParameterDescription
ContentOptional string parameter.
Specifies the JSON input as a string.
ContentPathOptional ITaskItem parameter.
Specifies the JSON input as a file path.
EmptyOptional string parameter.
Value to use as a replacement for empty values matched in JSON.
QueryRequired string parameter.
Specifies the JSONPath expression.
ResultOutput ITaskItem[] parameter.
Contains the results that are returned by the task.

You can either provide the path to a JSON file via ContentPath or provide the straight JSON content to Content. The Query is a JSONPath expression that is evaluated and returned via the Result task parameter. You can assign the resulting value to either a property (i.e. for a single value) or an item name (i.e. for multiple results).

JSON object properties are automatically projected as item metadata when assigning the resulting value to an item. For example, given the following JSON:

{
"http": {
"host": "localhost",
"port": 80,
"ssl": true
}
}

You can read the entire http value as an item with each property as a metadata value with:

<JsonPeekContentPath="host.json"Query="$.http">
<OutputTaskParameter="Result"ItemName="Http" />
</JsonPeek>

The Http item will have the following values (if it were declared in MSBuild):

<ItemGroup>
<HttpInclude="[item raw json]">
<host>localhost</host>
<port>80</port>
<ssl>true</ssl>
</Http>
</ItemGroup>

These item metadata values could be read as MSBuild properties as follows, for example:

<PropertyGroup>
<Host>@(Http -> '%(host)')</Host>
<Port>@(Http -> '%(port)')</Port>
<Ssl>@(Http -> '%(ssl)')</Ssl>
</PropertyGroup>

In addition to the explicitly opted in object properties, the entire node is available as raw JSON via the special _ (single underscore) metadata item.

If the matched value is empty, no items (because items cannot be constructed with empty identity) or property value will be returned. This makes it difficult to distinguish a successfully matched empty value from no value matched at all. For these cases, it's possible to specify an Empty value to stand-in for an empty (but successful) matched result instead, which allow to distinguish both scenarios:

<JsonPeekContent="$(Json)"Empty="$empty"Query="$(Query)">
<OutputTaskParameter="Result"PropertyName="Value" />
</JsonPeek>
<ErrorCondition="'$(Value)' == '$empty'"Text="The element $(Query) cannot have an empty value." />

JsonPoke Icon JsonPoke

VersionDownloads

Write values to JSON nodes selected with JSONPath

Usage:

 <JsonPokeContentPath="[JSON_FILE]"Query="[JSONPath]"Value="[VALUE]" />
<JsonPokeContentPath="[JSON_FILE]"Query="[JSONPath]"RawValue="[JSON]" />
<JsonPokeContent="[JSON]"Query="[JSONPath]"Value="[VALUE]" />

Parameters:

ParameterDescription
ContentOptional string input/output parameter.
Specifies the JSON input as a string and contains the updated
JSON after successful task execution.
ContentPathOptional ITaskItem parameter.
Specifies the JSON input as a file path.
QueryRequired string parameter.
Specifies the JSONPath expression.
ValueOptional ITaskItem[] parameter.
Specifies the value(s) to be inserted into the specified path.
RawValueOptional string parameter.
Specifies the raw (JSON) value to be inserted into the specified path.

You must either provide the path to a JSON file via ContentPath or raw JSON content via Content.

The Value can be an item group, and in that case, it will be inserted into the JSON node matching the JSONPath expression Query as an array. RawValue can be used to provide an entire JSON fragment as a string, with no conversion to an MSBuild item at all.

The existing JSON node will determine the data type of the value being written, so as to preserve the original document. Numbers, booleans and DateTimes are properly parsed before serializing to the node.

 <PropertyGroup>
<Json>
{
"http": {
"host": "localhost",
"port": 80,
"ssl": true
}
}
</Json>
</PropertyGroup>
<JsonPokeContent="$(Json)"Query="$.http.host"Value="example.com">
<OutputTaskParameter="Content"PropertyName="Json" />
</JsonPoke>
<JsonPokeContent="$(Json)"Query="$.http.port"Value="80">
<OutputTaskParameter="Content"PropertyName="Json" />
</JsonPoke>
<JsonPokeContent="$(Json)"Query="$.http.ssl"Value="true">
<OutputTaskParameter="Content"PropertyName="Json" />
</JsonPoke>
<MessageImportance="high"Text="$(Json)" />

Note how we update multiple values and assign the updated content to the same $(Json) property so it can be used in subsequent updates. The last Message task will render the following JSON:

{
"http": {
"host": "example.com",
"port": 80,
"ssl": true
}
}

NOTE: The port number was preserved as a number, as is the ssl boolean.

To force a value to be interpreted as a string, you can surround it with double or single quotes. For example, given the following JSON file:

{
"http": {
"ports": [
"80"
]
}
}

We can replace the ports array with string values as follows (without the explicit quotes, the values would be interpreted as numbers otherwise):

 <ItemGroup>
<HttpPortInclude="'8080'" />
<HttpPortInclude="'1080'" />
</ItemGroup>
<JsonPokeContentPath="http.json"Query="$.http.ports"Value="@(HttpPort)" />

Result:

{
"http": {
"ports": [
"8080", "1080"
]
}
}

It's also possible to write a complex object based on MSBuild item metadata:

 <ItemGroup>
<HttpInclude="Value">
<host>localhost</host>
<port>80</port>
<ssl>true</ssl>
</Value>
</ItemGroup>
<JsonPokeContentPath="http.json"Query="$.http"Value="@(Http)"Properties="host;port;ssl" />

Result:

{
"http": {
"host": "localhost",
"port": 80,
"ssl": true
}
}

Note how the native JSON type was automatically inferred, even though everything is basically a string in MSBuild. As noted above, you can surround any of the item metadata values in double or single quotes to force them to be written as strings instead.

The task can create entire object hierarchies if any segment of the path expression is not found, which makes it very easy to create complex structures by assigning a single value. For example, if the http section in the examples above didn't exist at all, the following task would add it automatically, prior to assigning the ssl property to true:

<JsonPokeContentPath="http.json"Query="$.http.ssl"Value="true" />

This also works for indexed queries, such as adding launch profile to launchSettings.json by simply assigning a value:

<JsonPokeContentPath="Properties\launchSettings.json"Query="$.profiles['IIS Express'].commandName"Value="IISExpress" />

which would create the following entry:

{
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
}
}
}

Array index is also supported as part of the query, to modify existing values. If the array is empty or non-existent, it's also possible to just use the index [0] to denote the new node should be the sole element in the new array, like for adding a new watch file value to host.json:

<JsonPokeContentPath="host.json"Query="$.watchFiles[0]"Value="myFile.txt" />

Which results in:

{
..."watchFiles": [ "myFile.txt" ]
}

It's quite common to want to add entries to an existing array, usually at the end of the array. The JSONPath syntax supports indexes that start from the end of the array (such as [-1:]), but if the array had any values already, that would match whichever is the last element, meaning in an update to that element's value. Since we need a different syntax for inserting a new node, starting from the end of the list, we leverage the C# syntax ^n where n is the position starting from the end. To add a new element at the end of the list, the index [^1] can be used. ^2 means prior to last and so on.

For example, to add a new watched file to the array in the example above, we could use:

<JsonPokeContentPath="host.json"Query="$.watchFiles[^1]"Value="myOtherFile.txt" />

Given an existing host.json file like the one above, we would get a new file added like so:

{
..."watchFiles": [ "myFile.txt", "myOtherFile.txt" ]
}

If the watchFiles property didn't exit at all or had no elements, the result would be the same as if we used [0], but this makes the code more flexible if needed.

The modified JSON nodes can be assigned to an item name using the Result task property, and will contain the item path (matching the Query plus the index if multiple nodes were modified) as well as the Value item metadata containing the raw JSON that was written.

Dogfooding

CI VersionBuild

We also produce CI packages from branches and pull requests so you can dogfood builds as quickly as they are produced.

The CI feed is https://pkg.kzu.app/index.json.

The versioning scheme for packages is:

  • PR builds: 42.42.42-pr[NUMBER]
  • Branch builds: 42.42.42-[BRANCH].[COMMITS]

Sponsors

Clarius OrgMFB Technologies, Inc.SandRockDRIVE.NET, Inc.Keith PickfordThomas BolonKori FrancisReuben SwartzJacob FosheeEric JohnsonJonathan Ken BonnySimon Croppagileworks-euZheyu ShenVezelChilliCream4OTCdomischellAdrian AlonsotorutekRyan McCafferySeika LogicielAndrew Granteska-gmbhGeodata AS

Sponsor this project

Learn more about GitHub Sponsors

About

JsonPeek and JsonPoke tasks implementations

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

11 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Used by

Contributors

Languages