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

feat: introduce verb visibility modifiers #1326

Closed
wants to merge 1 commit into from
Closed

Conversation

wesbillman
Copy link
Collaborator

@wesbillman wesbillman commented Apr 24, 2024

Fixes #1324

This adds the new schema changes and parser implementations. Once this PR lands, we'll need to update all the other repos to make sure they work with these breaking changes.

@alecthomas alecthomas mentioned this pull request Apr 24, 2024
@wesbillman wesbillman marked this pull request as ready for review April 24, 2024 22:22
@wesbillman wesbillman requested a review from a team as a code owner April 24, 2024 22:22
@wesbillman wesbillman requested review from worstell and removed request for a team April 24, 2024 22:22
val path: String?
)

private fun extractExportAnnotation(verb: KtNamedFunction, bindingContext: BindingContext): ExportAnnotation {
Copy link
Contributor

@worstell worstell Apr 25, 2024

Choose a reason for hiding this comment

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

nit- i think this can be accomplished without any member data and so it can be a static function declared in the companion object below, like the following:

private fun KtAnnotationEntry.toExportAnnotation(): ExportAnnotation {
      var visibility: Visibility? = null
      var ingress: Ingress? = null
      var method: Method? = null
      var path: String? = null
      exportAnnotation?.valueArguments?.forEach { arg ->
        when {
          arg.getArgumentName()?.asName?.asString() == "visibility" || arg.getArgumentExpression()?.getType(bindingContext)?.fqNameOrNull()?.asString() == Visibility::class.qualifiedName -> {
            visibility = kotlin.runCatching { Visibility.valueOf(arg.getArgumentExpression()?.text?.substringAfterLast('.') ?: "") }.getOrNull()
          }
          arg.getArgumentName()?.asName?.asString() == "ingress" || arg.getArgumentExpression()?.getType(bindingContext)?.fqNameOrNull()?.asString() == Ingress::class.qualifiedName -> {
            ingress = kotlin.runCatching { Ingress.valueOf(arg.getArgumentExpression()?.text?.substringAfterLast('.') ?: "") }.getOrNull()
          }
          arg.getArgumentName()?.asName?.asString() == "method" || arg.getArgumentExpression()?.getType(bindingContext)?.fqNameOrNull()?.asString() == Method::class.qualifiedName -> {
            method = kotlin.runCatching { Method.valueOf(arg.getArgumentExpression()?.text?.substringAfterLast('.') ?: "") }.getOrNull()
          }
          arg.getArgumentName()?.asName?.asString() == "path" || arg.getArgumentExpression()?.getType(bindingContext)?.fqNameOrNull()?.asString() == String::class.qualifiedName -> {
            path = arg.getArgumentExpression()?.text?.trim('"')
          }
        }
      }
      return ExportAnnotation(visibility, ingress, method, path)
    }

then to use it, you'd do annotationEntry.toExportAnnotation()

return verb.annotationEntries.firstOrNull {
bindingContext.get(BindingContext.ANNOTATION, it)?.fqName?.asString() == HttpIngress::class.qualifiedName
bindingContext.get(BindingContext.ANNOTATION, it)?.fqName?.asString() == Export::class.qualifiedName
Copy link
Contributor

@worstell worstell Apr 25, 2024

Choose a reason for hiding this comment

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

since we get the ingress information from the export annotation now, how about we pass the full KtAnnotationEntry instead of ExportAnnotation? then we won't need to derive it again and we can lift everything out of the let below. we can use annotationEntry.toExportAnnotation() to get the export fields

Request: &schema.Ref{Name: "EchoRequest"},
Response: &schema.Ref{Name: "EchoResponse"},
Name: "echo",
Visibility: "internal",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Use the constants here and elsewhere rather than literals - it will result in a compiler error if they get renamed, unlike the literals which will silently add invalid data.


Export bool `parser:"@'export'"`
Visibility schema.Visibility `parser:"@('public' | 'internal' | 'private')"`
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can we somehow catch //ftl:export (probably not here) and return an error indicating to use these now?

isVerb = true
if pctx.module.Name == "" {
pctx.module.Name = pctx.pkg.Name
} else if pctx.module.Name != pctx.pkg.Name {
pctx.errors.add(errorf(node, "function export directive must be in the module package"))
pctx.errors.add(errorf(node, "function visibility directive must be in the module package"))
Copy link
Collaborator

Choose a reason for hiding this comment

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

What does this error mean exctly? Must be in the root module package?

@wesbillman wesbillman closed this Apr 26, 2024
@wesbillman wesbillman deleted the verb-visibility branch September 3, 2024 20:52
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.

Rename ftl:export to ftl:verb and ftl:data
3 participants