moon
moon copied to clipboard
[feature] Improvements to code generation templates
Is your feature request related to a problem? Please describe.
Just some suggestions for the template creation DX
Describe the solution you'd like
I've come across a lot of things I'm wanted to do in the templates I'm writing, so I'm leaving the suggestions here. I'll try to keep them low-level and precise.
- [x] Sort prompts
Some template questions have a logical order. Like asking if you want to generate A before asking for details for A generation.
This can be achieved by making
variablesan array or adding a separatepromptsarray definition - [ ] Conditional prompts / variables Some prompts don't make sense depending on the answer to other prompts. Right now, the only way around this is
- [x] Internal variables
Allow template so specify variables cannot be changed from the CLI. This is useful for passing variables to the next templates in the chainto add
"only used if X == Y"to the prompt text - [ ] Dynamic template chain / conditional template extension
It would be really nice to allow an extended template to only be executed under certain conditions.
Right now this can be achieved by defining a variable in the first one that gets propagate to the next one.
The next template then uses that variable to determine the value of
skip, but that's a highly tight coupling. This could be implemented by allowingextendsto accept an object withskip(orcondition) condition that works like the one in template files frontmatter - [x] Automatic template help
This can be as simple as listing the template variables or showing the entire yaml on
moon generate TEMPLATE --helpIt would be nice to adecriptionordocsproperty to variables - [ ] Shared mutable memory properties
Some kind of shared in-memory object would help a lot. We don't need to make the entire context mutable, a
cachekey-value map in the Tera context that can be modified by any template would be enough I'm currently using extends to make a value available to all template files without copying and pasting code (imports do not work, but I think that is a Tera bug) - [x] Ability to iterate template
variablesThis would allow base templates to pattern match the variables which may be very handy (thinkbabel-plugin-*)
Minor things
skip vs condition
I find it odd to set when a file should be skipped instead of when it should run. To me, condition: {{ debug }} is more straightforward than skip: {{ not debug }} and I think it gets worse for more complex rules. Maybe it's just me, but I think there's a double negation hidden in there that always makes me write conditions wrong at the first time.
Idk, it seems to me that there are less checking to be done when I can say "do this if X" then "skip if X" because (in my mind) that unfolds to "do not generate if X" and then X becomes more complicated because if it is true I need to return false because I'm deciding if I should not do the thing... Idk, maybe I'm crazy lol
All great ideas. A few comments:
- Sort prompts - Would an
orderconfig for each prompt be enough for this? - Conditional prompts - This seems tricky, but maybe doable if other things land first.
- Internal variables - Easy enough.
- Dynamic template chain - Would have to look into.
- Automatic template help - We'll be adding template related commands in the future.
- Shared mutable memory properties - Would have to look into.
- Iterate variables - I think you can use
__tera_contextfor this: https://keats.github.io/tera/docs/#variables
@milesj great to hear there are! I see moon as the tool that will be always there, so the greater its template support the better! 🥳
Landing some of this here: https://github.com/moonrepo/moon/pull/1398
Looks like I forgot to actually send the detailed response:
- Sort prompts - Would an
orderconfig for each prompt be enough for this?
For sorting, yes. But if you ever want to support prompt flows, maybe it is better to move it to an array of objects.
- Conditional prompts - This seems tricky, but maybe doable if other things land first.
There's a way you can add features little by little and get conditional, and a more flexible prompt flow, way better than sorted
- Make it an array which allows ordering
- Make it a tree by add a
promptsproperty to a prompt. Order moves to a depth-first tree walk - add a
guard|whenproperty to the prompt, and only go down the tree if the parent value matches theguard
It could look something like this (I'm sure you'll pick better names):
variables:
- name: color
type: 'enum'
values: ['red', 'green']
default: 'red'
prompt: 'Favorite color?'
next:
# only one will execute
# but that can be decided by the tree visitor
# there's no need to pre-evaluate the flow
- case: 'red'
name: question_1
type: string
prompt: 'Name 3 red fruits'
next: # both will be executed
# no case here
- name: question_2
type: string
prompt: 'Another red question'
# neither here
- name: question_3
type: string
prompt: 'Another red question'
- case: 'green'
name: question_1
type: string
prompt: 'Name 3 mostly green country flags'
next:
- ...
- Iterate variables - I think you can use
__tera_contextfor this: https://keats.github.io/tera/docs/#variables
I tried but it doesn't work. As they say, it is a magical... I guess it is magical because you can't touch it, only print it lol
Landed some of these in v1.23.