Skip to content

Commit 198b091

Browse files
committed
feat: add feature Ideas document and link from roadmap
refactor: update interpolation syntax in documentation examples chore: add DotSettings for code inspection configuration
1 parent 2141dc6 commit 198b091

7 files changed

Lines changed: 206 additions & 17 deletions

File tree

docs/Feature-Ideas.md

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
# TinyTools Feature Ideas
2+
3+
This document collects small, focused feature ideas that fit TinyTools' core philosophy:
4+
5+
> Keep templates tiny, deterministic, dependency-light, and useful for data composition.
6+
7+
These ideas are not commitments. They are candidates to evaluate against the roadmap, implementation cost, and the project's goal of staying intentionally small.
8+
9+
---
10+
11+
## Recommended First Feature
12+
13+
### Template Diagnostics and Strict Mode
14+
15+
The strongest next feature candidate is a diagnostics layer with optional strict rendering.
16+
17+
Today, TinyTools is already useful for rendering deterministic text. The next quality-of-life improvement would be helping users find template mistakes before output is generated or shipped.
18+
19+
Possible API:
20+
21+
```csharp
22+
var diagnostics = engine.Analyze(template);
23+
24+
foreach (var diagnostic in diagnostics)
25+
{
26+
Console.WriteLine($"{diagnostic.Line}:{diagnostic.Column} {diagnostic.Message}");
27+
}
28+
```
29+
30+
Strict rendering could build on the same analysis model:
31+
32+
```csharp
33+
var engine = new TinyTemplateEngine(new TinyTemplateOptions
34+
{
35+
StrictVariables = true,
36+
StrictHelpers = true
37+
});
38+
```
39+
40+
Suggested diagnostics:
41+
42+
- Missing or unresolved variables
43+
- Unknown pipe helpers
44+
- Unmatched `@if`, `@foreach`, `@else`, or closing braces
45+
- Invalid null-coalescing or ternary expressions
46+
- Line and column information for template errors
47+
- Suggestions for common mistakes, such as misspelled helper names
48+
49+
Why it fits:
50+
51+
- Improves trust without making templates more powerful or complex
52+
- Supports existing validation work
53+
- Helps CLI, editor tooling, and future source-generator scenarios
54+
- Keeps error handling deterministic and easy to test
55+
56+
---
57+
58+
## Other Strong Candidates
59+
60+
### Render From JSON
61+
62+
TinyTools is often used for data composition, and JSON is a natural input format for templates. A first-class JSON render path would make examples, tests, CLIs, and automation easier.
63+
64+
Possible API:
65+
66+
```csharp
67+
var output = engine.RenderJson(template, json);
68+
```
69+
70+
Possible overloads:
71+
72+
```csharp
73+
var output = engine.RenderJson(template, jsonString);
74+
var output = engine.RenderJson(template, jsonDocument);
75+
var output = engine.RenderJsonFile(template, "data.json");
76+
```
77+
78+
Why it fits:
79+
80+
- Aligns with generating JSON, YAML, Markdown, config files, prompts, and emails
81+
- Makes CLI rendering easier to implement later
82+
- Gives users a simple bridge from external data into `ToolContext`
83+
84+
### Escaping Helpers
85+
86+
TinyTools is format-agnostic, so it should help users safely project values into common text formats without becoming an HTML view engine.
87+
88+
Possible helpers:
89+
90+
```text
91+
${Context.Name | json}
92+
${Context.Description | yaml}
93+
${Context.Value | csv}
94+
${Context.Text | markdown}
95+
```
96+
97+
Why it fits:
98+
99+
- Supports non-HTML output formats
100+
- Keeps escaping explicit in the template
101+
- Reduces accidental invalid JSON, CSV, YAML, or Markdown output
102+
103+
### Template Includes
104+
105+
Includes would allow reusable fragments while keeping templates simple.
106+
107+
Possible syntax:
108+
109+
```text
110+
@include("partials/header.tmpl")
111+
112+
Content here
113+
114+
@include("partials/footer.tmpl")
115+
```
116+
117+
Recommended design:
118+
119+
```csharp
120+
public interface ITemplateLoader
121+
{
122+
string Load(string path);
123+
}
124+
```
125+
126+
Why it fits:
127+
128+
- Enables reusable headers, footers, prompts, and generated-file fragments
129+
- Keeps file-system behavior outside the engine
130+
- Allows in-memory, embedded-resource, and file-based loaders
131+
132+
### Tiny CLI
133+
134+
A small command-line tool would make TinyTools useful outside application code.
135+
136+
Possible commands:
137+
138+
```bash
139+
tinytools render --template email.tmpl --data data.json --out email.txt
140+
tinytools validate --template email.tmpl --data data.json
141+
tinytools watch --template "*.tmpl" --data data.json --out output
142+
```
143+
144+
Why it fits:
145+
146+
- Makes the library easier to try
147+
- Supports automation and code-generation workflows
148+
- Provides a practical surface for diagnostics and JSON rendering
149+
150+
---
151+
152+
## Lower Priority Ideas
153+
154+
### File-Based Template Registry
155+
156+
Allow a registry to discover `.tmpl` files from a folder and render them by name.
157+
158+
This is useful, but it should probably come after includes and diagnostics so file templates have a clearer error model.
159+
160+
### Editor Tooling
161+
162+
Syntax highlighting, diagnostics, and preview tooling would be valuable. This should likely build on the diagnostics API rather than being implemented first.
163+
164+
### Source Generator Templates
165+
166+
Build-time template generation could be powerful, but it has a larger maintenance surface. It should probably wait until the parser, diagnostics, and strict behavior are stable.
167+
168+
---
169+
170+
## Guardrails
171+
172+
These feature ideas should preserve the current TinyTools boundaries:
173+
174+
- No HTML-first view rendering
175+
- No runtime code execution
176+
- No JavaScript engine
177+
- No heavy dependencies
178+
- No broad template DSL expansion
179+
- No hidden global file-system behavior
180+
181+
TinyTools should stay boring in the best way: predictable, inspectable, and easy to reason about.

roadmap.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,8 @@ dotnet tinytools watch --template *.tmpl
176176

177177
## Future Considerations (2027+)
178178

179+
Additional candidate features are tracked in [docs/Feature-Ideas.md](docs/Feature-Ideas.md). That document collects smaller ideas that may feed future roadmap updates.
180+
179181
### Under Consideration
180182

181183
#### ?? Localization/Internationalization

site/src/pages/api-reference.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ export function ApiReferencePage() {
2727
language="csharp"
2828
/>
2929
<p className="text-sm text-muted-foreground mt-2 mb-2">
30-
Replaces {"{PropertyName}"} tags with values from an anonymous object or class.
30+
Replaces {"${PropertyName}"} tags with values from an anonymous object or class.
3131
</p>
3232
<CodeBlock
33-
code={`var template = "Hello {FirstName} {LastName}!";
33+
code={`var template = "Hello \${FirstName} \${LastName}!";
3434
var model = new { FirstName = "John", LastName = "Smith" };
3535
var result = template.Interpolate(model);
3636
// Output: "Hello John Smith!"`}
@@ -44,10 +44,10 @@ var result = template.Interpolate(model);
4444
language="csharp"
4545
/>
4646
<p className="text-sm text-muted-foreground mt-2 mb-2">
47-
Replaces {"{Key}"} tags with values from a dictionary.
47+
Replaces {"${Key}"} tags with values from a dictionary.
4848
</p>
4949
<CodeBlock
50-
code={`var template = "Welcome to {City}, {Country}!";
50+
code={`var template = "Welcome to \${City}, \${Country}!";
5151
var data = new Dictionary<string, string>
5252
{
5353
{ "City", "Amsterdam" },

site/src/pages/getting-started.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ return (
3737
code={`using LowlandTech.TinyTools;
3838
3939
// Simple property interpolation
40-
var template = "Hello {FirstName} {LastName}!";
40+
var template = "Hello \${FirstName} \${LastName}!";
4141
var model = new { FirstName = "John", LastName = "Smith" };
4242
4343
var result = template.Interpolate(model);
@@ -57,12 +57,12 @@ var result = template.Interpolate(model);
5757
<CardContent className="space-y-4">
5858
<CodeBlock
5959
code={`var template = """
60-
Hi {CustomerName},
60+
Hi \${CustomerName},
6161
62-
Thank you for your order #{OrderNumber}.
62+
Thank you for your order #\${OrderNumber}.
6363
Your total is ${"${TotalAmount}"}.
6464
65-
We'll send a confirmation to {Email}.
65+
We'll send a confirmation to \${Email}.
6666
""";
6767
6868
var model = new

site/src/pages/home.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ const features = [
3232
];
3333

3434
const helloWorldExample = `// Simple string interpolation
35-
var template = "Hello {FirstName} {LastName}!";
35+
var template = "Hello \${FirstName} \${LastName}!";
3636
var model = new { FirstName = "John", LastName = "Smith" };
3737
3838
var result = template.Interpolate(model);`;
@@ -41,12 +41,12 @@ const helloWorldOutput = `Hello John Smith!`;
4141

4242
const emailExample = `// Email template example
4343
var template = """
44-
Hi {CustomerName},
44+
Hi \${CustomerName},
4545
46-
Thank you for your order #{OrderNumber}.
47-
Your total is {Total}.
46+
Thank you for your order #\${OrderNumber}.
47+
Your total is \${Total}.
4848
49-
We'll send confirmation to {Email}.
49+
We'll send confirmation to \${Email}.
5050
""";
5151
5252
var model = new

site/src/pages/variable-resolver.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,15 @@ return (
2222
<CardContent>
2323
<Tabs defaultValue="simple">
2424
<TabsList className="grid w-full grid-cols-2">
25-
<TabsTrigger value="simple">Simple {"{PropertyName}"}</TabsTrigger>
25+
<TabsTrigger value="simple">Simple ${"${PropertyName}"}</TabsTrigger>
2626
<TabsTrigger value="engine">Engine ${"${Context.xxx}"}</TabsTrigger>
2727
</TabsList>
2828
<TabsContent value="simple" className="space-y-4">
2929
<p className="text-sm text-muted-foreground">
30-
Use the <code>Interpolate</code> extension for quick, tag-based replacements.
30+
Use the <code>Interpolate</code> extension for quick, `${"${var}"}`-style replacements.
3131
</p>
3232
<CodeBlock
33-
code={`var template = "Hello {FirstName} {LastName}";
33+
code={`var template = "Hello \${FirstName} \${LastName}";
3434
var model = new { FirstName = "John", LastName = "Smith" };
3535
3636
var result = template.Interpolate(model);
@@ -41,7 +41,7 @@ var result = template.Interpolate(model);
4141
Dictionary models are also supported:
4242
</p>
4343
<CodeBlock
44-
code={`var template = "Hello {Name}";
44+
code={`var template = "Hello \${Name}";
4545
var model = new Dictionary<string, string> { ["Name"] = "Jane" };
4646
var result = template.Interpolate(model);
4747
// Output: Hello Jane`}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
2+
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=core/@EntryIndexedValue">True</s:Boolean>
3+
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=helpers/@EntryIndexedValue">True</s:Boolean>
4+
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=infrastructure/@EntryIndexedValue">True</s:Boolean>
5+
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=registry/@EntryIndexedValue">True</s:Boolean>
6+
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=templates/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

0 commit comments

Comments
 (0)