Search code examples
c#dotnet-cli

Add optional content in dotnet new templates in non c# files


I want to modify the content of README.md based on what the developer selects when creating a c# solution from the template. How do I do it?

I know that you can define

"symbols": {
    "EnableContent":{
        "type": "parameter",
        "dataType":"bool",
        "defaultValue": "true"
    }
}

in template.config/template.json to enable optional content in dotnet new templates.

In c# code, you can then use the defined symbol to include some code, if EnableContent is set to true (using c# preprocessor directives)

#if (EnableContent)
        public string foo()
        {
            return "bar";
        }

#endif

And in .cshtml it can be used like

@*#if (EnableContent)
<p>foobar</p>
#endif*@

Is there any way to add similar decision making in non c# files like markdown files (.md)? Or does this depend on c# preprocessor directives to be available? If so, is there any workaround to use c# preprocessor directives in markdown files in the context of using templates for dotnet new.

ps. I know that in this example I could just do two different versions of README.md and then select correct one using source modifiers

"sources": [
    {
        "modifiers": [
            {
                "condition": "(EnableContent)",
                "exclude": [ "README1.md" ]
            },
            {
                "condition": "(!EnableContent)",
                "exclude": [ "README2.md" ]
            }
        ]
    }

in template.config/template.json but my actual need more complex than that.


Solution

  • I eventually figure out this my self. There is a way, called SpecialCustomOperations, to define your own "language" to enable optional content in any text file.

    It is a bit badly documented feature, but I found great value from this answer to enable SpecialCustomOperations in markdown files.

    In template.config/template.json it is needed to define

    "SpecialCustomOperations": {
      "**/*.md": {
        "operations": [
          {
            "type": "conditional",
            "configuration": {
              "if": ["---#if"],
              "else": ["---#else"],
              "elseif": ["---#elseif", "---#elif"],
              "endif": ["---#endif"],
              "trim" : "true",
              "wholeLine": "true",
            }
          }
        ]
      }
    }
    

    Then following works

    ---#if (FooBar)
    Foo bar
    ---#elif (BarBaz)
    Bar baz
    ---#else
    Baz qux
    ---#endif
    

    In addition, I found that you can define similar operations for csproj files (that is basically xml). There you need to define (following an example in this commnent)

    "SpecialCustomOperations": {
    "**/*.xaml": {
      "operations": [
        {
          "type": "conditional",
          "configuration": {
            "actionableIf": [ "<!--#if" ],
            "actionableElse": [ "#else", "<!--#else" ],
            "actionableElseif": [ "#elseif", "<!--#elseif" ],
            "endif": [ "#endif", "<!--#endif" ],
            "trim" : "true",
            "wholeLine": "true",
          }
        }
      ]
    }
    }
    

    ps. list of filetypes where Special Operations are enabled by default can be found here. In other filetypes it is needed to define SpecialCustomOperations by hand.