Skip to content

Commit fe3991c

Browse files
committed
Initial commit
#1
1 parent 4f7d11b commit fe3991c

10 files changed

Lines changed: 791 additions & 2 deletions

Plugins.Json.sln

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 17
4+
VisualStudioVersion = 17.12.35728.132
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FlowSynx.Plugins.Json", "src\FlowSynx.Plugins.Json.csproj", "{46F69BA2-2760-4A30-A813-FDDEE427C068}"
7+
EndProject
8+
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{DEC33F76-6AA7-41D1-9ADE-C5CFC3B1185C}"
9+
EndProject
10+
Global
11+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
12+
Debug|Any CPU = Debug|Any CPU
13+
Release|Any CPU = Release|Any CPU
14+
EndGlobalSection
15+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
16+
{46F69BA2-2760-4A30-A813-FDDEE427C068}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
17+
{46F69BA2-2760-4A30-A813-FDDEE427C068}.Debug|Any CPU.Build.0 = Debug|Any CPU
18+
{46F69BA2-2760-4A30-A813-FDDEE427C068}.Release|Any CPU.ActiveCfg = Release|Any CPU
19+
{46F69BA2-2760-4A30-A813-FDDEE427C068}.Release|Any CPU.Build.0 = Release|Any CPU
20+
EndGlobalSection
21+
GlobalSection(SolutionProperties) = preSolution
22+
HideSolutionNode = FALSE
23+
EndGlobalSection
24+
GlobalSection(NestedProjects) = preSolution
25+
{46F69BA2-2760-4A30-A813-FDDEE427C068} = {DEC33F76-6AA7-41D1-9ADE-C5CFC3B1185C}
26+
EndGlobalSection
27+
EndGlobal

README.md

Lines changed: 183 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,183 @@
1-
# plugin-json
2-
FlowSynx plugin to loads and parses local JSON files. Supports transformation, extraction, and mapping of hierarchical data structures in workflows.
1+
# FlowSynx JSON Plugin
2+
3+
The **FlowSynx JSON Plugin** is a built-in, plug-and-play integration for the FlowSynx automation engine. It enables parsing, transforming, extracting, and mapping structured or semi-structured JSON data within workflows with no custom coding required.
4+
5+
This plugin is automatically installed by the FlowSynx engine when selected in the workflow builder. It is not intended for standalone developer usage outside the FlowSynx platform.
6+
7+
---
8+
9+
## Purpose
10+
11+
The JSON Plugin allows FlowSynx users to:
12+
13+
- Parse and inspect complex JSON structures.
14+
- Extract values using JSONPath.
15+
- Flatten nested objects.
16+
- Map JSON data to specific output fields using flexible rules.
17+
18+
It integrates seamlessly into FlowSynx no-code/low-code workflows.
19+
20+
---
21+
22+
## Supported Operations
23+
24+
- **extract**: Extracts a specific value using a `jsonPath` expression.
25+
- **transform**: Flattens a nested JSON structure into flat `key: value` pairs.
26+
- **map**: Maps fields to new keys using a dictionary of JSONPath expressions.
27+
28+
---
29+
30+
## Input Parameters
31+
32+
Below are the parameters accepted by the plugin:
33+
34+
- `Operation` (string): Required. The type of operation to perform. Supported values are `extract`, `transform`, and `map`.
35+
- `Json` (string): Required. The raw JSON string to process.
36+
- `jsonPath` (string): Required for `extract` operation. A JSONPath expression to locate a specific value.
37+
- `Mappings` (dictionary): Required for `map` operation. A dictionary where each key is an output field and each value is a JSONPath expression.
38+
- `Flatten` (bool): Optional. Used with `transform` to specify whether to flatten nested objects (`true`) or not (`false`).
39+
40+
Example input:
41+
```json
42+
{
43+
"Operation": "map",
44+
"Json": "{...}",
45+
"jsonPath": "$.some.path",
46+
"Mappings": {
47+
"Name": "$.person.name",
48+
"Email": "$.person.contact.email"
49+
},
50+
"Flatten": true
51+
}
52+
```
53+
54+
---
55+
56+
## Operation Examples
57+
58+
### extract Operation
59+
60+
**Input JSON:**
61+
```json
62+
{
63+
"meta": {
64+
"version": "1.0.2",
65+
"timestamp": "2024-12-01T10:00:00Z"
66+
}
67+
}
68+
```
69+
70+
**Input Parameters:**
71+
```json
72+
{
73+
"Operation": "extract",
74+
"Json": "{...}",
75+
"jsonPath": "$.meta.version"
76+
}
77+
```
78+
79+
**Output:**
80+
```json
81+
"1.0.2"
82+
```
83+
84+
---
85+
86+
### transform Operation
87+
88+
**Input JSON:**
89+
```json
90+
{
91+
"user": {
92+
"profile": {
93+
"name": "Bob",
94+
"email": "bob@example.com"
95+
}
96+
}
97+
}
98+
```
99+
100+
**Input Parameters:**
101+
```json
102+
{
103+
"Operation": "transform",
104+
"Json": "{...}",
105+
"Flatten": true
106+
}
107+
```
108+
109+
**Output:**
110+
```json
111+
{
112+
"user.profile.name": "Bob",
113+
"user.profile.email": "bob@example.com"
114+
}
115+
```
116+
117+
---
118+
119+
### map Operation
120+
121+
**Input JSON:**
122+
```json
123+
{
124+
"person": {
125+
"name": "Alice",
126+
"contact": {
127+
"email": "alice@example.com"
128+
}
129+
}
130+
}
131+
```
132+
133+
**Input Parameters:**
134+
```json
135+
{
136+
"Operation": "map",
137+
"Json": "{...}",
138+
"Mappings": {
139+
"Name": "$.person.name",
140+
"Email": "$.person.contact.email"
141+
}
142+
}
143+
```
144+
145+
**Output:**
146+
```json
147+
{
148+
"Name": "Alice",
149+
"Email": "alice@example.com"
150+
}
151+
```
152+
153+
---
154+
155+
## Example Use Case in FlowSynx
156+
157+
1. Add the JSON plugin to your FlowSynx workflow.
158+
2. Set `Operation` to one of: `extract`, `transform`, or `map`.
159+
3. Provide the JSON input string.
160+
4. Configure `jsonPath`, `Mappings`, or `Flatten` depending on the operation.
161+
5. Use the output downstream in your workflow.
162+
163+
---
164+
165+
## Debugging Tips
166+
167+
- If the result is null, ensure `jsonPath` is valid and points to an existing element.
168+
- If nothing is mapped, check for typos in the JSONPath expressions inside `Mappings`.
169+
- If the result isn't flattened, double-check that `Flatten` is set to `true`.
170+
171+
---
172+
173+
## Security Notes
174+
175+
- No data is persisted unless explicitly configured.
176+
- All operations run in a secure sandbox within FlowSynx.
177+
- Only authorized platform users can view or modify configurations.
178+
179+
---
180+
181+
## License
182+
183+
Copyright FlowSynx. All rights reserved.

src/FlowSynx.Plugins.Json.csproj

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net9.0</TargetFramework>
5+
<ImplicitUsings>enable</ImplicitUsings>
6+
<Nullable>enable</Nullable>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="FlowSynx.PluginCore" Version="1.3.0" />
11+
</ItemGroup>
12+
13+
<ItemGroup>
14+
<Compile Update="Resources.Designer.cs">
15+
<DesignTime>True</DesignTime>
16+
<AutoGen>True</AutoGen>
17+
<DependentUpon>Resources.resx</DependentUpon>
18+
</Compile>
19+
</ItemGroup>
20+
21+
<ItemGroup>
22+
<EmbeddedResource Update="Resources.resx">
23+
<Generator>ResXFileCodeGenerator</Generator>
24+
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
25+
</EmbeddedResource>
26+
</ItemGroup>
27+
28+
<ItemGroup>
29+
<None Update="flowsynx.png">
30+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
31+
</None>
32+
<None Update="README.md">
33+
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
34+
</None>
35+
</ItemGroup>
36+
37+
</Project>

src/JsonPlugin.cs

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
using FlowSynx.PluginCore;
2+
using FlowSynx.PluginCore.Extensions;
3+
using FlowSynx.PluginCore.Helpers;
4+
using FlowSynx.Plugins.Json.Models;
5+
using Newtonsoft.Json.Linq;
6+
7+
namespace FlowSynx.Plugins.Json;
8+
9+
public class JsonPlugin : IPlugin
10+
{
11+
private IPluginLogger? _logger;
12+
private bool _isInitialized;
13+
14+
public PluginMetadata Metadata
15+
{
16+
get
17+
{
18+
return new PluginMetadata
19+
{
20+
Id = Guid.Parse("61519421-6eb9-466b-aaed-366098da1922"),
21+
Name = "Json",
22+
CompanyName = "FlowSynx",
23+
Description = Resources.PluginDescription,
24+
Version = new PluginVersion(1, 0, 0),
25+
Category = PluginCategory.Data,
26+
Authors = new List<string> { "FlowSynx" },
27+
Copyright = "© FlowSynx. All rights reserved.",
28+
Icon = "flowsynx.png",
29+
ReadMe = "README.md",
30+
RepositoryUrl = "https://github.com/flowsynx/plugin-json",
31+
ProjectUrl = "https://flowsynx.io",
32+
Tags = new List<string>() { "flowSynx", "json", "data", "data-platform" }
33+
};
34+
}
35+
}
36+
37+
public PluginSpecifications? Specifications { get; set; }
38+
39+
public Type SpecificationsType => typeof(JsonPluginSpecifications);
40+
41+
private Dictionary<string, Func<JObject, InputParameter, object>> OperationMap => new(StringComparer.OrdinalIgnoreCase)
42+
{
43+
["extract"] = HandleExtract,
44+
["map"] = HandleMap,
45+
["transform"] = HandleTransform
46+
};
47+
48+
public IReadOnlyCollection<string> SupportedOperations => new[] { "extract", "map", "transform" };
49+
50+
public Task Initialize(IPluginLogger logger)
51+
{
52+
if (ReflectionHelper.IsCalledViaReflection())
53+
throw new InvalidOperationException(Resources.ReflectionBasedAccessIsNotAllowed);
54+
55+
ArgumentNullException.ThrowIfNull(logger);
56+
_logger = logger;
57+
_isInitialized = true;
58+
return Task.CompletedTask;
59+
}
60+
61+
public async Task<object?> ExecuteAsync(PluginParameters parameters, CancellationToken cancellationToken)
62+
{
63+
if (ReflectionHelper.IsCalledViaReflection())
64+
throw new InvalidOperationException(Resources.ReflectionBasedAccessIsNotAllowed);
65+
66+
if (!_isInitialized)
67+
throw new InvalidOperationException($"Plugin '{Metadata.Name}' v{Metadata.Version} is not initialized.");
68+
69+
var inputParameter = parameters.ToObject<InputParameter>();
70+
var operation = inputParameter.Operation;
71+
72+
if (OperationMap.TryGetValue(operation, out var handler))
73+
{
74+
var json = inputParameter.Json ?? throw new ArgumentException("Input JSON is required.");
75+
var jsonObj = JObject.Parse(json);
76+
77+
return handler(jsonObj, inputParameter);
78+
}
79+
80+
throw new NotSupportedException($"Json plugin: Operation '{operation}' is not supported.");
81+
}
82+
83+
private object HandleExtract(JObject json, InputParameter inputParameter)
84+
{
85+
string? path = inputParameter.jsonPath;
86+
if (string.IsNullOrWhiteSpace(path))
87+
throw new ArgumentException("jsonPath parameter is required for extract.");
88+
89+
var token = json.SelectToken(path);
90+
return token?.ToString() ?? "null";
91+
}
92+
93+
private object HandleMap(JObject json, InputParameter inputParameter)
94+
{
95+
if (inputParameter.Mappings == null)
96+
throw new InvalidOperationException("Mappings not defined in specifications.");
97+
98+
var result = new Dictionary<string, object?>();
99+
foreach (var kvp in inputParameter.Mappings)
100+
{
101+
result[kvp.Key] = json.SelectToken(kvp.Value)?.ToString();
102+
}
103+
104+
return result;
105+
}
106+
107+
private object HandleTransform(JObject json, InputParameter inputParameter)
108+
{
109+
var result = json;
110+
111+
if (inputParameter.Flatten)
112+
result = FlattenJson(json);
113+
114+
return result;
115+
}
116+
117+
private JObject FlattenJson(JObject input)
118+
{
119+
var result = new JObject();
120+
121+
void Flatten(JObject obj, string prefix)
122+
{
123+
foreach (var prop in obj.Properties())
124+
{
125+
var path = string.IsNullOrEmpty(prefix) ? prop.Name : $"{prefix}.{prop.Name}";
126+
if (prop.Value is JObject nested)
127+
Flatten(nested, path);
128+
else
129+
result[path] = prop.Value;
130+
}
131+
}
132+
133+
Flatten(input, "");
134+
return result;
135+
}
136+
}

0 commit comments

Comments
 (0)