From 2a5702e945e5bc22113d10030e777ce54c395e9c Mon Sep 17 00:00:00 2001 From: Noueman Khalikine Date: Wed, 12 May 2021 19:20:36 +0200 Subject: [PATCH 1/4] Added api_doc templates and check-examples scripts --- .generator/templates/api_doc.mustache | 75 +++++++++++++++++++++++++++ check-examples.sh | 17 ++++++ extract-code-blocks.awk | 71 +++++++++++++++++++++++++ extract-code-blocks.sh | 12 +++++ 4 files changed, 175 insertions(+) create mode 100644 .generator/templates/api_doc.mustache create mode 100755 check-examples.sh create mode 100755 extract-code-blocks.awk create mode 100755 extract-code-blocks.sh diff --git a/.generator/templates/api_doc.mustache b/.generator/templates/api_doc.mustache new file mode 100644 index 000000000000..2e566fd3bc6e --- /dev/null +++ b/.generator/templates/api_doc.mustache @@ -0,0 +1,75 @@ +# {{moduleName}}.{{classname}}{{#description}} + +{{description}}{{/description}} + +All URIs are relative to *{{basePath}}* + +Method | HTTP request | Description +------------- | ------------- | ------------- +{{#operations}}{{#operation}}[**{{operationId}}**]({{classname}}.md#{{operationId}}) | **{{httpMethod}}** {{path}} | {{#summary}}{{summary}}{{/summary}} +{{/operation}}{{/operations}} + +{{#operations}} +{{#operation}} +# **{{{operationId}}}** +> {{#returnType}}{{{returnType}}} {{/returnType}}{{{operationId}}}({{#requiredParams}}{{^defaultValue}}{{paramName}}{{^-last}}, {{/-last}}{{/defaultValue}}{{/requiredParams}}) + +{{#notes}} +{{{notes}}} +{{/notes}} + +### Example + + +```typescript +import { {{{moduleName}}} } from '{{{projectName}}}'; + +const apiInstance = new {{{moduleName}}}.{{classname}}(); + +{{#allParams}} +// {{{dataType}}}{{#description}} | {{{description}}}{{/description}}{{^required}} (optional){{/required}} +let {{paramName}} = {{{example}}}; + +{{/allParams}} +apiInstance.{{{operationId}}}({{#allParams}}{{{paramName}}}{{^-last}}, {{/-last}}{{/allParams}}).then((data) => { + console.log('API called successfully. Returned data: ' + data); +}).catch((error) => console.error(error)); +``` + + +### Parameters +{{^hasParams}}This endpoint does not need any parameter.{{/hasParams}}{{#allParams}}{{#-last}} +Name | Type | Description | Notes +------------- | ------------- | ------------- | -------------{{/-last}}{{/allParams}} +{{#allParams}}{{^defaultValue}} **{{paramName}}** | {{^isPrimitiveType}}**{{{dataType}}}**{{/isPrimitiveType}}{{#isPrimitiveType}}**{{dataType}}**{{/isPrimitiveType}}| {{description}} | +{{/defaultValue}}{{/allParams}}{{#allParams}}{{#defaultValue}} **{{paramName}}** | {{^isPrimitiveType}}{{^isEnum}}**{{dataType}}**{{/isEnum}}{{/isPrimitiveType}}{{#isPrimitiveType}}[**{{dataType}}**]{{/isPrimitiveType}}{{#isEnum}}{{#allowableValues}}{{#enumVars}}{{#-first}}**Array<{{/-first}}{{value}}{{^-last}} | {{/-last}}{{#-last}}>**{{/-last}}{{/enumVars}}{{/allowableValues}}{{/isEnum}} | {{description}} |{{^required}} (optional){{/required}} defaults to {{{.}}} +{{/defaultValue}}{{/allParams}} + +### Return type + +{{#returnType}}{{#returnTypeIsPrimitive}}**{{{returnType}}}**{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}**{{{returnType}}}**{{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}void (empty response body){{/returnType}} + +### Authorization + +{{^authMethods}}No authorization required{{/authMethods}}{{#authMethods}}[{{{name}}}](README.md#{{{name}}}){{^-last}}, {{/-last}}{{/authMethods}} + +### HTTP request headers + + - **Content-Type**: {{#consumes}}{{{mediaType}}}{{^-last}}, {{/-last}}{{/consumes}}{{^consumes}}Not defined{{/consumes}} + - **Accept**: {{#produces}}{{{mediaType}}}{{^-last}}, {{/-last}}{{/produces}}{{^produces}}Not defined{{/produces}} + +{{#responses.0}} + +### HTTP response details +| Status code | Description | Response headers | +|-------------|-------------|------------------| +{{#responses}} +**{{code}}** | {{message}} | {{#headers}} * {{baseName}} - {{description}}
{{/headers}}{{^headers.0}} - {{/headers.0}} | +{{/responses}} +{{/responses.0}} + +[[Back to top]](#) [[Back to API list]](README.md#documentation-for-api-endpoints) [[Back to Model list]](README.md#documentation-for-models) [[Back to README]](README.md) + +{{/operation}} +{{/operations}} + diff --git a/check-examples.sh b/check-examples.sh new file mode 100755 index 000000000000..be7aa69ce6b8 --- /dev/null +++ b/check-examples.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +if [ $# -eq 0 ]; then + echo "No arguments supplied" + exit 2 +fi + +# Docker setup +yarn + +./extract-code-blocks.sh examples $1 + +ls examples/$1/*.ts | xargs -P $(($(nproc)*2)) -n 1 yarn tsc +if [ $? -ne 0 ]; then + echo -e "Failed to build examples" + exit 1 +fi diff --git a/extract-code-blocks.awk b/extract-code-blocks.awk new file mode 100755 index 000000000000..10e346c6cfad --- /dev/null +++ b/extract-code-blocks.awk @@ -0,0 +1,71 @@ +#!/usr/bin/env -S awk -f +# SPDX-License-Identifier: Apache-2.0 OR MIT +# Based on https://codereview.stackexchange.com/questions/194986/print-code-fenced-sections-of-a-markdown-document/195030#195030 +BEGIN { + in_code_block = 0; + tag = ""; + operation_id = ""; +} + +function slug(value) { + head = ""; + tail = value; + while ( match(tail,/[[:upper:]][[:lower:]]/) ) { + tgt = substr(tail,RSTART,1); + if ( substr(tail,RSTART-1,1) ~ /[[:lower:]]/ || RSTART > 1 ) { + tgt = "-" tolower(tgt); + } + head = head substr(tail,1,RSTART-1) tgt; + tail = substr(tail,RSTART+1); + } + return tolower(head) tail; +} + +function camel(value) { + gsub("_ip_", "_iP_", value); + gsub("_id_", "_iD_", value); + + head = toupper(substr(value,0,1)) substr(value,2); + while ( match(head, /_([a-z])/) ) { + head = substr(head,0,RSTART-1) toupper(substr(head,RSTART+1, 1)) substr(head,RSTART+2) + } + # NOTE special cases for all caps groups which we can't handle otherwise + gsub("Aws", "AWS", head); + gsub("Gcp", "GCP", head); + return head; +} + +/^# datadog_api_client\.v[0-9]*\.(.+)Api/ { + tag = slug(substr($2, 23, length($2)-25)); +} +/^##? \*\*.+\*\*/ { + operation_id = camel(substr($2, 3, length($2)-4)); +} +/^```typescript/ { + if (in_code_block == 0) { + in_code_block = 1; + if (out_file) { + close(out_file); + } + system("mkdir -p " output "/" tag); + out_file=output "/" tag "/" operation_id ".ts"; + print out_file; + } else { + print "Can't parse " FILENAME > "/dev/stderr" + exit 1 + } + next; +} +/^```/ { + in_code_block = 0; +} + +in_code_block { + # Make sure that the file is newly created + if (in_code_block == 1) { + in_code_block = 2; + print > out_file; + } else { + print >> out_file; + } +} diff --git a/extract-code-blocks.sh b/extract-code-blocks.sh new file mode 100755 index 000000000000..7d8e612f1f69 --- /dev/null +++ b/extract-code-blocks.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +OUTPUT=${1:-examples} +VERSIONS=${2:-v1,v2} + +cd ${0%/*} + +VERSIONS=(${VERSIONS//,/ }) + +for version in "${VERSIONS[@]}"; do + ls packages/datadog-api-client-$version/*Api.md| xargs -n1 ./extract-code-blocks.awk -v output="${OUTPUT}/$version" +done From f57869e61e3ae7e28b9a14c50e411a1ba30ab5b2 Mon Sep 17 00:00:00 2001 From: Noueman Khalikine Date: Thu, 20 May 2021 12:35:38 +0200 Subject: [PATCH 2/4] added example generation scripts, updated api_doc template --- .generator/templates/api_doc.mustache | 26 +++++++++++++++++--------- check-examples.sh | 14 ++++++++++++-- extract-code-blocks.awk | 8 ++++---- extract-code-blocks.sh | 2 +- 4 files changed, 34 insertions(+), 16 deletions(-) diff --git a/.generator/templates/api_doc.mustache b/.generator/templates/api_doc.mustache index 2e566fd3bc6e..6887c631d03e 100644 --- a/.generator/templates/api_doc.mustache +++ b/.generator/templates/api_doc.mustache @@ -1,4 +1,4 @@ -# {{moduleName}}.{{classname}}{{#description}} +# {{projectName}}.{{moduleName}}.{{classname}}{{#description}} {{description}}{{/description}} @@ -11,7 +11,7 @@ Method | HTTP request | Description {{#operations}} {{#operation}} -# **{{{operationId}}}** +## **{{{operationId}}}** > {{#returnType}}{{{returnType}}} {{/returnType}}{{{operationId}}}({{#requiredParams}}{{^defaultValue}}{{paramName}}{{^-last}}, {{/-last}}{{/defaultValue}}{{/requiredParams}}) {{#notes}} @@ -23,17 +23,26 @@ Method | HTTP request | Description ```typescript import { {{{moduleName}}} } from '{{{projectName}}}'; +import * as fs from 'fs'; -const apiInstance = new {{{moduleName}}}.{{classname}}(); +const configuration = {{{moduleName}}}.createConfiguration(); +const apiInstance = new {{{moduleName}}}.{{classname}}(configuration); +{{#hasParams}} +let body:{{{moduleName}}}.{{classname}}{{operationIdCamelCase}}Request = { {{#allParams}} -// {{{dataType}}}{{#description}} | {{{description}}}{{/description}}{{^required}} (optional){{/required}} -let {{paramName}} = {{{example}}}; - + // {{{dataType}}}{{#description}} | {{{description}}}{{/description}}{{^required}} (optional){{/required}} + {{paramName}}: {{{example}}}, {{/allParams}} -apiInstance.{{{operationId}}}({{#allParams}}{{{paramName}}}{{^-last}}, {{/-last}}{{/allParams}}).then((data) => { +}; +{{/hasParams}} +{{^hasParams}} +let body:any = {}; +{{/hasParams}} + +apiInstance.{{{operationId}}}(body).then((data:any) => { console.log('API called successfully. Returned data: ' + data); -}).catch((error) => console.error(error)); +}).catch((error:any) => console.error(error)); ``` @@ -72,4 +81,3 @@ Name | Type | Description | Notes {{/operation}} {{/operations}} - diff --git a/check-examples.sh b/check-examples.sh index be7aa69ce6b8..bba77bc58843 100755 --- a/check-examples.sh +++ b/check-examples.sh @@ -5,12 +5,22 @@ if [ $# -eq 0 ]; then exit 2 fi -# Docker setup +# install dependencies yarn ./extract-code-blocks.sh examples $1 -ls examples/$1/*.ts | xargs -P $(($(nproc)*2)) -n 1 yarn tsc +# temporary fix to compile example files +find examples/$1 -type f -name "*.ts" | xargs sed -i.bak 's_datadog-api-client_../../../index_1' + +# cp tsconfig.json examples/$1 + +touch examples/$1/tsconfig.json + +echo '{"compilerOptions":{"strict":true,"target":"es5","module":"commonjs","moduleResolution":"node","declaration":true,"esModuleInterop":true,"resolveJsonModule":true,"noImplicitAny":true,"noImplicitThis":true,"noUnusedLocals":false,"noUnusedParameters":false,"noImplicitReturns":true,"noFallthroughCasesInSwitch":true,"sourceMap":true,"noLib":false,"lib":["es5","es6","es7"]},"exclude":["dist","features","node_modules"],"include":["./**/*.ts"]}' > examples/$1/tsconfig.json + +yarn tsc --build examples/$1 + if [ $? -ne 0 ]; then echo -e "Failed to build examples" exit 1 diff --git a/extract-code-blocks.awk b/extract-code-blocks.awk index 10e346c6cfad..a885b392fff5 100755 --- a/extract-code-blocks.awk +++ b/extract-code-blocks.awk @@ -35,11 +35,11 @@ function camel(value) { return head; } -/^# datadog_api_client\.v[0-9]*\.(.+)Api/ { - tag = slug(substr($2, 23, length($2)-25)); +/^# datadog-api-client\.v[0-9]*\.(.+)Api/ { + tag = substr($2, 23, length($2)-25); } -/^##? \*\*.+\*\*/ { - operation_id = camel(substr($2, 3, length($2)-4)); +match($0, /^##? \*\*(.+)\*\*/) { + operation_id = substr($2, 3, length($2)-4) } /^```typescript/ { if (in_code_block == 0) { diff --git a/extract-code-blocks.sh b/extract-code-blocks.sh index 7d8e612f1f69..beef66acc051 100755 --- a/extract-code-blocks.sh +++ b/extract-code-blocks.sh @@ -8,5 +8,5 @@ cd ${0%/*} VERSIONS=(${VERSIONS//,/ }) for version in "${VERSIONS[@]}"; do - ls packages/datadog-api-client-$version/*Api.md| xargs -n1 ./extract-code-blocks.awk -v output="${OUTPUT}/$version" + ls docs/$version/*Api.md| xargs -n1 ./extract-code-blocks.awk -v output="${OUTPUT}/$version" done From 14942bb1fcddd51f77f424d2d1264c100bcb9555 Mon Sep 17 00:00:00 2001 From: Noueman Khalikine Date: Fri, 21 May 2021 13:48:28 +0200 Subject: [PATCH 3/4] fixed camel and slug functions in awk script --- check-examples.sh | 2 -- extract-code-blocks.awk | 12 ++++++------ 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/check-examples.sh b/check-examples.sh index bba77bc58843..01ce89ecf48e 100755 --- a/check-examples.sh +++ b/check-examples.sh @@ -13,8 +13,6 @@ yarn # temporary fix to compile example files find examples/$1 -type f -name "*.ts" | xargs sed -i.bak 's_datadog-api-client_../../../index_1' -# cp tsconfig.json examples/$1 - touch examples/$1/tsconfig.json echo '{"compilerOptions":{"strict":true,"target":"es5","module":"commonjs","moduleResolution":"node","declaration":true,"esModuleInterop":true,"resolveJsonModule":true,"noImplicitAny":true,"noImplicitThis":true,"noUnusedLocals":false,"noUnusedParameters":false,"noImplicitReturns":true,"noFallthroughCasesInSwitch":true,"sourceMap":true,"noLib":false,"lib":["es5","es6","es7"]},"exclude":["dist","features","node_modules"],"include":["./**/*.ts"]}' > examples/$1/tsconfig.json diff --git a/extract-code-blocks.awk b/extract-code-blocks.awk index a885b392fff5..3d16e4e999ad 100755 --- a/extract-code-blocks.awk +++ b/extract-code-blocks.awk @@ -10,9 +10,9 @@ BEGIN { function slug(value) { head = ""; tail = value; - while ( match(tail,/[[:upper:]][[:lower:]]/) ) { + while ( match(tail,/[A-Z][a-z]/) ) { tgt = substr(tail,RSTART,1); - if ( substr(tail,RSTART-1,1) ~ /[[:lower:]]/ || RSTART > 1 ) { + if ( substr(tail,RSTART-1,1) ~ /[a-z]/ || RSTART > 1 ) { tgt = "-" tolower(tgt); } head = head substr(tail,1,RSTART-1) tgt; @@ -25,7 +25,7 @@ function camel(value) { gsub("_ip_", "_iP_", value); gsub("_id_", "_iD_", value); - head = toupper(substr(value,0,1)) substr(value,2); + head = toupper(substr(value,1,1)) substr(value,2); while ( match(head, /_([a-z])/) ) { head = substr(head,0,RSTART-1) toupper(substr(head,RSTART+1, 1)) substr(head,RSTART+2) } @@ -36,10 +36,10 @@ function camel(value) { } /^# datadog-api-client\.v[0-9]*\.(.+)Api/ { - tag = substr($2, 23, length($2)-25); + tag = slug(substr($2, 23, length($2)-25)); } -match($0, /^##? \*\*(.+)\*\*/) { - operation_id = substr($2, 3, length($2)-4) +/^##? \*\*.+\*\*/ { + operation_id = camel(substr($2, 3, length($2)-4)) } /^```typescript/ { if (in_code_block == 0) { From 1b46153e7566d0d8d1b2b6d33b1e2d60389cff06 Mon Sep 17 00:00:00 2001 From: Noueman Khalikine Date: Fri, 21 May 2021 17:15:12 +0200 Subject: [PATCH 4/4] ignore examples folder --- .gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 343ffd08cae5..1eebfa9ba227 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,4 @@ node_modules package-lock.json @rerun.txt -node_modules +examples