NeVeSpl / NTypewriter

File/code generator using Scriban text templates populated with C# code metadata from Roslyn API.
https://nevespl.github.io/NTypewriter/
MIT License
126 stars 25 forks source link

How to use builtin function LINQ.Where in template? #117

Closed jons-bakerhill closed 5 months ago

jons-bakerhill commented 6 months ago

I'm trying to use https://github.com/NeVeSpl/NTypewriter/blob/master/Documentation/BuiltInFunctions.md#where

My issue is easy to reproduce using the online example generator at https://nevespl.github.io/NTypewriter/?exampleId=type02 adding my snippets at line 4 (inside the for class in data.Classes loop)

If I add {{ class.Properties | Where("x => x != null") }} I get the error

10:27:56.499 : <input>(4,37) Value cannot be null.
Parameter name: predicate
10:27:56.499 : Rendering template failed

If I try without the quotes {{ class.Properties | Where(x => x != null) }} I get the error messages

10:28:28.610 : <input>(4,37) Error while parsing assign expression: Expression is only allowed for a top level assignment in: <target_expression> = <value_expression>
10:28:28.610 : <input>(4,40) Error while parsing assign expression: Expecting <expression> instead of `>` in: <target_expression> = <value_expression>
10:28:28.610 : <input>(4,40) Expecting a comma to separate arguments in a function call.
10:28:28.610 : <input>(4,40) Expecting an expression for argument function calls instead of this token.
10:28:28.611 : <input>(4,40) Expecting a closing parenthesis for a function call.
10:28:28.611 : <input>(4,51) Invalid token found `)`. Expecting <EOL>/end of line.
10:28:28.611 : <input>(4,47) Error while parsing capture statement: The <end> statement was not found in: capture <variable> ... end
10:28:28.611 : <input>(4,47) Error while parsing for statement: The <end> statement was not found in: for <variable> in <expression> ... end
10:28:28.611 : Rendering template failed

If I try {{ class.Properties.Where("x => x != null") }} I get

10:30:14.505 : <input>(4,29) Cannot get member with name Where.

{{ class.Properties | LINQ.Where("x => x != null") }} gives me

10:31:22.751 : <input>(4,31) The variable or function `LINQ` was not found

On a side note is it possible to fail the build when using the source generator instead of "succeeding" and just writing the log file?

NeVeSpl commented 6 months ago

The correct syntax is

for class in data.Classes | Where 'x => x.Name.StartsWith("Pro")'

but as it was announced here: https://github.com/NeVeSpl/NTypewriter/releases/tag/v0.5.5

it only works in VS add-in, it does not work with online and source generator versions.

jons-bakerhill commented 6 months ago

Is there a good way to check the new-ish SetMethod.IsPublic when using the source generator without explicitly looping the properties one by one? i.e. an equivalent to class.Properties.Where(x => x?.SetMethod?.IsPublic == true)

NeVeSpl commented 6 months ago

You can write custom function, and put that expression inside a function.

an example can be found here: https://github.com/NeVeSpl/NTypewriter/blob/1ba4036e8543cbe9b5284c0278f79307588d295f/DocumentationGenerator/Configuration.nt.cs#L39-L42

jons-bakerhill commented 5 months ago

That worked.

On a different topic when creating a console app using Buildalyzer (like the doc generator for NTypeWriter itself [1]) it seems that file path information is lost. I've poked around a bit and my best guess is that it's lost or not created by Buildalyzer but I'm not sure. Is there a way to get/keep that data around? In the source generator version I added a "generated from file at path src/xyz/abc.cs" and I'd like to keep that. My fallback is to use the namespace and class name but that isn't always consistent with the path or project.

[1] https://github.com/NeVeSpl/NTypewriter/blob/1ba4036e8543cbe9b5284c0278f79307588d295f/DocumentationGenerator/Program.cs

NeVeSpl commented 5 months ago

Do you mean a path to the file where a symbol is located?

That should work, it is also used for generating documentation: https://github.com/NeVeSpl/NTypewriter/blob/1ba4036e8543cbe9b5284c0278f79307588d295f/DocumentationGenerator/Configuration.nt.cs#L49-L60

jons-bakerhill commented 5 months ago

I'm using the block below in the template and the location.Path property is null in the GetRelativePath function. The C# console app is a mildly modified version of the Documentation Generator Program.cs

// DO NOT EDIT This file was generated by NTypeWriter
// from the C# class with path(s) 
   {{- for location in symbol.Locations }}
// {{ GetRelativePath(location.Path, symbol) }}
   {{- end }}

Using the same template and function with the source generator variant location.Path is not null.

I can put together a minimal test case tomorrow if needed. I was hoping it was something more obvious,

jons-bakerhill commented 5 months ago

It appears the paths get lost when trying to render models from projects referenced by the directly loaded project. Explicitly loading all the projects I care about [1] seems to get/keep all the file paths. That's a usable workaround for me.

[1] manager.GetProject(projectPath).AddToWorkspace(workspace)