-
Notifications
You must be signed in to change notification settings - Fork 629
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
yaml: implement basic Swagger/OpenAPI subparser #3245
Conversation
* | ||
* This source code is released for free distribution under the terms of the | ||
* GNU General Public License version 2 or (at your option) any later version. | ||
* |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you add references for the target language or input like:
Line 12 in 8215492
* GDScript language reference: |
git push --force
is welcome.
Codecov Report
@@ Coverage Diff @@
## master #3245 +/- ##
==========================================
+ Coverage 84.98% 85.31% +0.32%
==========================================
Files 207 208 +1
Lines 49324 49525 +201
==========================================
+ Hits 41916 42250 +334
+ Misses 7408 7275 -133
Continue to review full report at Codecov.
|
Writing a subparser on the YAML parser is an incredible challenge! |
Is there any difference between the targets, Swagger 2.0 and Openapi 3.0.x? |
The parser is able to parse both Swagger 2.0 and Openapi 3.0.x. The code is partly based on ansible playbook parser. It was tested using the following vim's TagBar parser declaration: let g:tagbar_type_yaml = { \ 'ctagstype': 'openapi', \ 'kinds': [ \ 'p:path', \ 'd:schema', \ 'P:parameter', \ 'R:response', \ ] \ }
bb573fd
to
36a38b0
Compare
KEY_PATHS, | ||
}; | ||
|
||
static const enum openapiKeys responses3Keys[] = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any difference between the targets, Swagger 2.0 and Openapi 3.0.x?
They are 2 different revisions of the protocol (Swagger == OpenAPI 2.0). They are mostly the same except for several details (not interesting for ctags) and several sections have a distinct path in yaml (e.g. "responses" in swagger and "components.responses" for openapi). I tried to express it in XXXKeys
names with 2 (swagger) or 3 (openapi). pathKeys
is the same for both.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. Thank you.
swagger: '2.0' | ||
info: | ||
description: test | ||
title: test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about tagging the title?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If it makes sense to tag all user-defined entities, then ok.
But then more fields must be tagged:
- info itself
- servers children
- webhooks children
- security children
- tags children
I don't think the following entities worth adding tags (too minor IMHO):
- openapi
- jsonSchemaDialect
- externalDocs
https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#openapi-object
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also the items of "components": https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#fixed-fields-6
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
added
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The way I wrote is wrong.
In 97915e7, your parser extracts "title".
However, what I expected is your parser extract "test" in "title: test".
version: '1.0' | ||
|
||
servers: | ||
- url: http://example.com |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about tagging the URLs under servers?
@@ -0,0 +1,55 @@ | |||
openapi: 3.0.0 | |||
info: | |||
title: test |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about tagging the title?
parsers/openapi.c
Outdated
{ DEPTYPE_SUBPARSER, "Yaml", &openapiSubparser }, | ||
}; | ||
|
||
parserDefinition* const def = parserNew ("OpenApi"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems that OpenAPI may be better than OpenApi.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, no problem
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
renamed
Though I named the yaml parser "Yaml", I think "OpenAPI" is better than "OpenApi" as the name of your parser. (The review is in progress.) |
parsers/openapi.c
Outdated
def->kindTable = OpenApiKinds; | ||
def->kindCount = ARRAY_SIZE (OpenApiKinds); | ||
def->parser = findOpenApiTags; | ||
def->useCork = CORK_NIL; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CORK_NIL
is not suitable value for useCork
field.
The useCork
field is initialized with 0 in parserNew. So you don't have to give a value to the field as far as your parser doesn't need cork indexes. Let's remove this line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, fixed
parsers/openapi.c
Outdated
return def; | ||
} | ||
|
||
/* vi:set tabstop=4 shiftwidth=4: */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is .editorconfig not enough?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it was a copy-pasted line from ansible parser, removed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, sorry, I wonder where it came from because I don't use vim:-).
parsers/openapi.c
Outdated
yaml_token_t *token) | ||
{ | ||
int i; | ||
for (i = 0; i < ARRAY_SIZE(tagSources); i++) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will you maintain this parser?
If the answer is "yes", you can choose your favorite C coding style.
If the answer is "no", I would like you to follow the ctags' coding style like:
for (i = 0; i < ARRAY_SIZE(tagSources); i++)
{
...
See the position of {
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
parsers/openapi.c
Outdated
openapi->type_stack, | ||
ts->keys, | ||
ts->countKeys | ||
)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Impressive technique. I must rewrite the ansibleplaybook.c with this technique.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks :)
parsers/openapi.c
Outdated
|
||
static void inputEnd(subparser *s) | ||
{ | ||
Assert (((struct sOpenApiSubparser*)s)->type_stack == NULL); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even if a broken input is given to the parser, we can expect the type_stack becomes empty at the end of parsing?
If we cannot expect it, we should clear the stack here instead of doing "Assert".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, done
parsers/openapi.c
Outdated
|
||
static enum openapiKeys parseKey(yaml_token_t *token) | ||
{ | ||
if (scalarNeq(token, 10, "components")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For mapping from "string" to a key, you can use functions defined in main/keyword.h.
I write this here is not for performance. With the function, the code of this parser can be more declarative.
This parser is really nice. The technique used in this parser excites me. In past years, I have been thinking about YPATH, something like XPath but for YAML. I'm reading openapi spec slowly. What should be tagged or should not be tagged is not so obvious to me. |
handleKey and handleValue do the same with different tables. diff --git a/parsers/openapi.c b/parsers/openapi.c
index 9e26aecdf..493f32ed1 100644
--- a/parsers/openapi.c
+++ b/parsers/openapi.c
@@ -447,13 +447,15 @@ const struct tagSource tagValueSources[] = {
},
};
-static void handleKey(struct sOpenApiSubparser *openapi,
- yaml_token_t *token)
+static void handleToken(struct sOpenApiSubparser *openapi,
+ yaml_token_t *token,
+ const struct tagSource tss[],
+ size_t ts_count)
{
int i;
- for (i = 0; i < ARRAY_SIZE(tagSources); i++)
+ for (i = 0; i < ts_count; i++)
{
- const struct tagSource* ts = &tagSources[i];
+ const struct tagSource* ts = &tss[i];
if (stateStackMatch(
openapi->type_stack,
@@ -473,31 +475,17 @@ static void handleKey(struct sOpenApiSubparser *openapi,
}
}
+static void handleKey(struct sOpenApiSubparser *openapi,
+ yaml_token_t *token)
+{
+ handleToken (openapi, token, tagSources, ARRAY_SIZE(tagSources));
+}
+
static void handleValue(struct sOpenApiSubparser *openapi,
yaml_token_t *token)
{
- int i;
- for (i = 0; i < ARRAY_SIZE(tagValueSources); i++)
- {
- const struct tagSource* ts = &tagValueSources[i];
-
- if (stateStackMatch(
- openapi->type_stack,
- ts->keys,
- ts->countKeys
- ))
- {
- // printf("match value! i=%d\n", i);
-
- tagEntryInfo tag;
- initTagEntry (&tag, (char *)token->data.scalar.value, ts->kind);
- attachYamlPosition (&tag, token, false);
-
- makeTagEntry (&tag);
- break;
- }
- }
+ handleToken (openapi, token, tagValueSources, ARRAY_SIZE(tagValueSources));
}
static void openapiPlayStateMachine (struct sOpenApiSubparser *openapi, |
I'm OK with that. |
yaml: implement basic Swagger/OpenAPI subparser
#3254 is merged. Thank you. |
here: #3258 |
The parser is able to parse both Swagger 2.0 and Openapi 3.0.x.
The code is partly based on ansible playbook parser. It was tested
using the following vim's TagBar parser declaration: