Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for using local json templates as modules #3367

Merged
merged 13 commits into from
Jul 13, 2021

Conversation

shenglol
Copy link
Contributor

@shenglol shenglol commented Jun 24, 2021

This is still a work in progress. Things to do:

  • Fix FileWatherTests and add tests
  • Module path completion for .json files (I'll send a follow-up PR to implement this)

Closes #3160.


namespace Bicep.Core.Syntax.Converters
{
public static class StatementSyntaxConverter
Copy link
Contributor Author

@shenglol shenglol Jun 24, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The source code of the converters is basically copied from the decompiler with some tweaks. We cannot use the decompiler directly here because: 1) I wanted to avoid having Core reference Decompiler; 2) it won't work when a JSON template contains a nested template.

@shenglol shenglol marked this pull request as ready for review June 29, 2021 12:42
: CreateSyntaxTree(fileUri, fileContents);

public static SyntaxTree CreateSyntaxTree(Uri fileUri, string fileContents) =>
PathHelper.HasBicepExtension(fileUri) || !PathHelper.HasAnyExtension(fileUri)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

HasAnyExtension

Maybe I missed it elsewhere, but we are rather strict in what we allow as a module path. I think we should restrict the extensions we use to reference JSON templates. (We can always add more later, but once we open it up fully, we can never use any other extension in the path.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good pt. I'll reverse the logic so that it will only create JSON modules if the extension is .{json,jsonc,arm}.

@majastrz
Copy link
Member

public static class TestTypeHelper

General test strategy question: The decompiler was always a best effort tool, but now we are adding decompiler-like logic to the core.

If we added a new type or some additional type metadata to the JSON, we'll need to remember to update this logic so we can convert it back into a contract bicep file.

Is there something we could do to catch it? Maybe take all the Valid bicep test cases we have and try to use them as a module via both JSON and Bicep and then query the semantic model to see if there's any diff?


Refers to: src/Bicep.Core.UnitTests/Utils/TestTypeHelper.cs:19 in f98d3f1. [](commit_id = f98d3f1, deletion_comment = False)

@majastrz
Copy link
Member

public static class TestTypeHelper

Or maybe take any data set that compiles, run its JSON through the converter logic and then see if the outputs and params match?


In reply to: 871043323


Refers to: src/Bicep.Core.UnitTests/Utils/TestTypeHelper.cs:19 in f98d3f1. [](commit_id = f98d3f1, deletion_comment = False)

@shenglol
Copy link
Contributor Author

shenglol commented Jul 6, 2021

If we added a new type or some additional type metadata to the JSON, we'll need to remember to update this logic so we can convert it back into a contract bicep file.

Yeah this is definitely something that should be guarded by tests.

Or maybe take any data set that compiles, run its JSON through the converter logic and then see if the outputs and params match?

I like it. I'll add a data set test in this way.


namespace Bicep.Core.Syntax
{
public class JsonSyntaxTree : SyntaxTree
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you considered representing the template semantically without actually generating a syntax tree? My concern with extending SyntaxTree is just that it's a corner case to maintain with quite different behavior. e.g. when raising diagnostics or doing type analysis, it'll be a subtlety that could easily be missed, or add complexity to the code, when it feels like there are real meaningful differences between a 'real' syntax tree and a generated one. Providing an accurate decompilation also feels like it could be a maintenance overhead in the long run which may not be necessary if we avoid generating syntax.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, actually my original design was like that (to create a different semantic module for ARM templates), but I switch to the current approach to the existing semantic model and type checker as much as possible. Now I realize it might not be worth it given the maintenance overhead. @majastrz also raised the a similar concern (in the comments on adding tests to ensure the converters and the decompiler logic are in sync). It won't be too hard to switch back to my original design since I still have the code, but I would like to have a discussion with you and Marcin before moving forward.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As we discussed offline, I've refactored the code to create a different semantic model for JSON templates, which removes the converters and avoids extending SyntaxTree.

@@ -1,1829 +1,1914 @@
{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is odd...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should to be due to line endings normalization which is expected.


namespace Bicep.Core.Syntax
{
public class SyntaxTree
public class SyntaxTree : ISourceFile
Copy link
Contributor Author

@shenglol shenglol Jul 12, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per our discussion offline, I'm going to rename the class to BicepFile in a follow-up PR. I've created #3560 to track it.

@majastrz
Copy link
Member

I played with the VSIX a bit. I really like how even unchanged JSON changes are noticed by the consuming Bicep file in VS code.


ValidateTemplate(template);

var templateObject = JObject.Parse(fileContents, new JsonLoadSettings
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JsonLoadSettings

Does the default duplicate property behavior match the runtime? Should we set it explicitly?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it matches (the runtime does not specify DuplicatePropertyNameHandling).

Copy link
Member

@majastrz majastrz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

@shenglol shenglol enabled auto-merge (squash) July 13, 2021 04:01
@shenglol shenglol merged commit b416c57 into main Jul 13, 2021
@shenglol shenglol deleted the shenglol/local-json-file-as-module branch July 13, 2021 04:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Allow module references to be local template json files
4 participants