Skip to content

Commit 7692b0f

Browse files
committed
docs
1 parent b1cd547 commit 7692b0f

File tree

3 files changed

+174
-0
lines changed

3 files changed

+174
-0
lines changed

docs/Contributing.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,9 @@ We follow the same versioning as https://github.com/dotnet/sdk and release branc
6666
| Development | *main* |
6767
| Release | *release/** |
6868

69+
# Ways to contribute
70+
71+
- [create new generated symbol type](./contributing/how-to-create-new-generated-symbol.md)
72+
- [create new value form](./contributing/how-to-create-new-value-form.md)
73+
6974
[Top](#top)
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# How to create new generated symbol type
2+
3+
Available generated symbol types are described [here](../Available-Symbols-Generators.md).
4+
Generated symbols are processed by a corresponding macro component that can generate new variables before the template is instantiated. New variables can be created from other variables (usually parameters) or independently.
5+
6+
We appreciate creating new types of generated symbols and macros by the community.
7+
8+
Generated symbols follow the following syntax:
9+
```json
10+
{
11+
"symbols":
12+
{
13+
"symbolName":
14+
{
15+
"type": "generated",
16+
"generator": "your-type", //type of generated symbol; should be same as type of the macro implementing it
17+
"dataType": "string", //data type of the value that symbol generates: "string", "choice", "bool", "float", "int", "hex", "text"
18+
"parameters":
19+
{
20+
"name": "value" //key-value parameters for the symbol. The value may be JSON array or object, if more complicated configuration is needed.
21+
},
22+
"replaces": "to-be-replaced", // the text to replace with the value of this symbol in template content
23+
"fileRename": "to-be-replaced", // defines the portion of file name which will be replaced by symbol value
24+
}
25+
26+
}
27+
}
28+
```
29+
30+
To create new generated symbol type, follow the following guideline
31+
32+
1. Implement [`Microsoft.TemplateEngine.Orchestrator.RunnableProjects.Abstractions.IGeneratedSymbolMacro<T>`](../../src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/Abstractions/IGeneratedSymbolMacro.cs) interface.
33+
34+
Any macro implementation is a component ([`IIdentifiedComponent`](../../src/Microsoft.TemplateEngine.Abstractions/IIdentifiedComponent.cs)) and will be loaded by template engine.
35+
The existing implementation macro components are located in [`Macros`](../../src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/Macros) folder of `Microsoft.TemplateEngine.Orchestrator.RunnableProjects` projects.
36+
37+
The implementation should have:
38+
- `Id` property - unique GUID for component
39+
- `Type` property - unique `string` name, matching generated symbol type
40+
- `Evaluate(IEngineEnvironmentSettings environmentSettings, IVariableCollection variables, T config)` method - evaluates the variables based on `config` specified
41+
- `Evaluate(IEngineEnvironmentSettings environmentSettings, IVariableCollection variables, IGeneratedSymbolConfig generatedSymbolConfig)` method - evaluates the variables based on `generatedSymbolConfig` specified
42+
- `CreateConfig(IEngineEnvironmentSettings environmentSettings, IGeneratedSymbolConfig generatedSymbolConfig)` method - creates macro-specific configuration from `generatedSymbolConfig`, that later on can be passed to `Evaluate` method
43+
44+
You may want to derive your own implementation from `BaseGeneratedSymbolMacro<T>` base class that offers some common logic. Configuration of the macro may derive from `BaseMacroConfig` class, that already have some utilities to parse the JSON configuration.
45+
When using base class, you need to implement the following members:
46+
- `Id` and `Type` properties assigned to constant unique values
47+
- `Evaluate` method: the method should create new variables to `IVariableCollection variableCollection` using parsed `config` and existing variables. It is recommended to log errors and debug information using logger available from `environmentSettings`. If you need to access the file system, do so via `environmentSettings.Host.FileSystem` abstraction.
48+
- `CreateConfig` method - creates macro specific config from `IGeneratedSymbolConfig` config.
49+
50+
The very basic implementation may be:
51+
```CSharp
52+
internal class HelloMacro : BaseGeneratedSymbolMacro<HelloMacroConfig>
53+
{
54+
public override string Type => "hello";
55+
56+
public override Guid Id { get; } = new Guid("342BC62F-8FED-4E5A-AB59-F9AB98030155");
57+
58+
public override void Evaluate(IEngineEnvironmentSettings environmentSettings, IVariableCollection variableCollection, HelloMacroConfig config)
59+
{
60+
string greetings = $"Hello {config.NameToGreet}!";
61+
//set configured variable to Hello Name!
62+
variableCollection[config.VariableName] = greetings;
63+
environmentSettings.Host.Logger.LogDebug("[{macro}]: Variable '{var}' was assigned to value '{value}'.", nameof(HelloMacro), config.VariableName, greetings);
64+
}
65+
66+
protected override HelloMacroConfig CreateConfig(IGeneratedSymbolConfig generatedSymbolConfig) => new(this, generatedSymbolConfig);
67+
}
68+
69+
internal class HelloMacroConfig : BaseMacroConfig<HelloMacro, HelloMacroConfig>
70+
{
71+
internal HelloMacroConfig(HelloMacro macro, string variableName, string? dataType = null, string nameToGreet) : base(macro, variableName, dataType)
72+
{
73+
if (string.IsNullOrEmpty(nameToGreet))
74+
{
75+
throw new ArgumentException($"'{nameof(nameToGreet)}' cannot be null or empty.", nameof(nameToGreet));
76+
}
77+
78+
NameToGreet = nameToGreet;
79+
}
80+
81+
internal HelloMacroConfig(HelloMacro macro, IGeneratedSymbolConfig generatedSymbolConfig)
82+
: base(macro, generatedSymbolConfig.VariableName, generatedSymbolConfig.DataType)
83+
{
84+
NameToGreet = GetMandatoryParameterValue(generatedSymbolConfig, nameof(NameToGreet));
85+
}
86+
87+
internal string NameToGreet { get; }
88+
}
89+
```
90+
91+
`IGeneratedSymbolConfig` config already contains the pre-parsed JSON from template.json. It has properties for: symbol name, data type (if specified) and parameters collection.
92+
Parameters collection contains parameter key-value pairs from JSON. Note that value is in JSON format, i.e. if the parameter value is string, the it contains `"\"string-value\""`.
93+
It is recommend to get `JToken` using `JToken.Parse` on this value when parsing the value or use helper methods available in `BaseMacroConfig` that can parse the data.
94+
95+
2. Once the macro is implemented, add it to [components collection](../../src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/Components.cs).
96+
97+
3. [optional] Update [JSON schema](../../src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/Schemas/JSON/template.json) with new generated symbol syntax.
98+
If you do so, also add [a new test case](../../test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/SchemaTests/GeneratorTest.json) for testing the syntax.
99+
100+
4. Add unit tests for new implementation. Macro related unit tests are located in [this folder](../../test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/MacroTests/).
101+
For more complete scenario, consider adding the full template generation tests to [`RunnableProjectGeneratorTests.cs`](../../test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/RunnableProjectGeneratorTests.cs).
102+
103+
5. Update documentation in [docs folder](../Available-Symbols-Generators.md).
104+
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# How to create a new value form
2+
3+
Available value forms are described [here](../Runnable-Project-Templates---Value-Forms.md).
4+
Value form represent the form of the parameter, usually related to specific casing.
5+
6+
We appreciate creating new value forms by the community.
7+
8+
Value forms follow the following syntax:
9+
```json
10+
{
11+
"forms":
12+
{
13+
"nameOfTheForm":
14+
{
15+
"identifier": "name-unique", //type of value form; should be unique value
16+
"param1": "value1", //key-value parameters for the form. The value may be JSON array or object, if more complicated configuration is needed.
17+
"param2": "value2"
18+
}
19+
}
20+
}
21+
```
22+
23+
To create new value form, follow the following guideline:
24+
25+
1. Implement [`Microsoft.TemplateEngine.Orchestrator.RunnableProjects.ValueForms.IValueFormFactory`](../../src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms/IValueFormFactory.cs) interface.
26+
27+
The existing implementation of value form are located in [`ValueForms`](../../src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueForms) folder of `Microsoft.TemplateEngine.Orchestrator.RunnableProjects` projects.
28+
29+
The implementation should have:
30+
- `Identifier` property - unique identifier of the form
31+
- `Type` property - unique `string` name, matching generated symbol type
32+
- `Create(string? name = null)` method - creates the form for default configuration
33+
- `FromJObject(string name, JObject? configuration = null)` method - creates the form for json configuration
34+
35+
The `IValueForm` has `Identifier` property that matches factory `Identifier`, `Name` corresponding the name of the form in JSON and `Process` method that create the form for the passed `value`.
36+
37+
You may want to derive your own implementation from one of the base classes:
38+
- `BaseValueFormFactory` - basic features
39+
- `ActionableValueFormFactory`- the form that just does the action without configuration
40+
- `ConfigurableValueFormFactory`- the form that performs the action and based on configuration
41+
- `DependantValueFormFactory` - the form that needs other forms for processing
42+
43+
The very basic implementation may be:
44+
```CSharp
45+
internal class HelloValueForm : ActionableValueFormFactory
46+
{
47+
internal const string FormIdentifier = "hello";
48+
49+
public HelloValueForm() : base(FormIdentifier)
50+
{
51+
}
52+
53+
protected override string Process(string value) => $"Hello {value}!";
54+
}
55+
```
56+
57+
2. Once the value form is implemented, add it to [value form collection](../../src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/ValueFormRegistry.cs).
58+
59+
3. [optional] Update [JSON schema](../../src/Microsoft.TemplateEngine.Orchestrator.RunnableProjects/Schemas/JSON/template.json) with new value form syntax.
60+
If you do so, also add [a new test case](../../test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/SchemaTests/) for testing the syntax.
61+
62+
4. Add unit tests for new implementation. Macro related unit tests are located in [this folder](../../test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/ValueFormTests/).
63+
For more complete scenario, consider adding the full template generation tests to [`RunnableProjectGeneratorTests.cs`](../../test/Microsoft.TemplateEngine.Orchestrator.RunnableProjects.UnitTests/RunnableProjectGeneratorTests.cs).
64+
65+
5. Update documentation in [docs folder](../Runnable-Project-Templates---Value-Forms.md).

0 commit comments

Comments
 (0)