private/apigen: Fix TS generator to apply naming conventions
Fix the TypeScript generator to generate code using the common TypeScript conventions. Closes https://github.com/storj/storj/issues/6360 Change-Id: I244896feea389670eca0df95d3ac58e25d600e14
This commit is contained in:
parent
71c9547de5
commit
47f344927d
@ -10,9 +10,8 @@ import (
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/text/cases"
|
||||
"golang.org/x/text/language"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"storj.io/storj/private/api"
|
||||
)
|
||||
@ -122,17 +121,25 @@ func isNillableType(t reflect.Type) bool {
|
||||
}
|
||||
|
||||
// compoundTypeName create a name composed with base and parts, by joining base as it's and
|
||||
// capitalizing each part.
|
||||
// capitalizing each part. base is not altered.
|
||||
func compoundTypeName(base string, parts ...string) string {
|
||||
caser := cases.Title(language.Und)
|
||||
titled := make([]string, len(parts))
|
||||
for i := 0; i < len(parts); i++ {
|
||||
titled[i] = caser.String(parts[i])
|
||||
titled[i] = capitalize(parts[i])
|
||||
}
|
||||
|
||||
return base + strings.Join(titled, "")
|
||||
}
|
||||
|
||||
func capitalize(s string) string {
|
||||
r, size := utf8.DecodeRuneInString(s)
|
||||
if size <= 0 {
|
||||
return s
|
||||
}
|
||||
|
||||
return string(unicode.ToTitle(r)) + s[size:]
|
||||
}
|
||||
|
||||
type typeAndName struct {
|
||||
Type reflect.Type
|
||||
Name string
|
||||
|
@ -273,7 +273,7 @@ func (p Param) namedType(ep Endpoint, where string) reflect.Type {
|
||||
if p.Type.Name() == "" {
|
||||
return typeCustomName{
|
||||
Type: p.Type,
|
||||
name: compoundTypeName(ep.GoName, where, "param", p.Name),
|
||||
name: compoundTypeName(ep.TypeScriptName, where, "param", p.Name),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -22,43 +22,43 @@ export class Version {
|
||||
number: number;
|
||||
}
|
||||
|
||||
export class getResponseItem {
|
||||
export class GetResponseItem {
|
||||
id: UUID;
|
||||
path: string;
|
||||
date: Time;
|
||||
metadata: Metadata;
|
||||
last_retrievals?: getResponseItemLastretrievals;
|
||||
last_retrievals?: GetResponseItemLastRetrievals;
|
||||
}
|
||||
|
||||
export class getResponseItemLastretrievalsItem {
|
||||
export class GetResponseItemLastRetrievalsItem {
|
||||
user: string;
|
||||
when: Time;
|
||||
}
|
||||
|
||||
export class updateContentRequest {
|
||||
export class UpdateContentRequest {
|
||||
content: string;
|
||||
}
|
||||
|
||||
export class updateContentResponse {
|
||||
export class UpdateContentResponse {
|
||||
id: UUID;
|
||||
date: Time;
|
||||
pathParam: string;
|
||||
body: string;
|
||||
}
|
||||
|
||||
export type getResponse = Array<getResponseItem>
|
||||
export type GetResponse = Array<GetResponseItem>
|
||||
|
||||
export type getResponseItemLastretrievals = Array<getResponseItemLastretrievalsItem>
|
||||
export type GetResponseItemLastRetrievals = Array<GetResponseItemLastRetrievalsItem>
|
||||
|
||||
export class docsHttpApiV0 {
|
||||
export class DocsHttpApiV0 {
|
||||
private readonly http: HttpClient = new HttpClient();
|
||||
private readonly ROOT_PATH: string = '/api/v0/docs';
|
||||
|
||||
public async get(): Promise<getResponse> {
|
||||
public async get(): Promise<GetResponse> {
|
||||
const fullPath = `${this.ROOT_PATH}/`;
|
||||
const response = await this.http.get(fullPath);
|
||||
if (response.ok) {
|
||||
return response.json().then((body) => body as getResponse);
|
||||
return response.json().then((body) => body as GetResponse);
|
||||
}
|
||||
const err = await response.json();
|
||||
throw new Error(err.error);
|
||||
@ -94,14 +94,14 @@ export class docsHttpApiV0 {
|
||||
throw new Error(err.error);
|
||||
}
|
||||
|
||||
public async updateContent(request: updateContentRequest, path: string, id: UUID, date: Time): Promise<updateContentResponse> {
|
||||
public async updateContent(request: UpdateContentRequest, path: string, id: UUID, date: Time): Promise<UpdateContentResponse> {
|
||||
const u = new URL(`${this.ROOT_PATH}/${path}`);
|
||||
u.searchParams.set('id', id);
|
||||
u.searchParams.set('date', date);
|
||||
const fullPath = u.toString();
|
||||
const response = await this.http.post(fullPath, JSON.stringify(request));
|
||||
if (response.ok) {
|
||||
return response.json().then((body) => body as updateContentResponse);
|
||||
return response.json().then((body) => body as UpdateContentResponse);
|
||||
}
|
||||
const err = await response.json();
|
||||
throw new Error(err.error);
|
||||
|
@ -85,7 +85,7 @@ func (f *tsGenFile) registerTypes() {
|
||||
}
|
||||
|
||||
func (f *tsGenFile) createAPIClient(group *EndpointGroup) {
|
||||
f.pf("\nexport class %sHttpApi%s {", group.Prefix, strings.ToUpper(f.api.Version))
|
||||
f.pf("\nexport class %sHttpApi%s {", capitalize(group.Prefix), strings.ToUpper(f.api.Version))
|
||||
f.pf("\tprivate readonly http: HttpClient = new HttpClient();")
|
||||
f.pf("\tprivate readonly ROOT_PATH: string = '%s/%s';", f.api.endpointBasePath(), group.Prefix)
|
||||
for _, method := range group.endpoints {
|
||||
|
@ -156,7 +156,8 @@ func (types *Types) GenerateTypescriptDefinitions() string {
|
||||
|
||||
for _, t := range allStructs {
|
||||
func() {
|
||||
pf("\nexport class %s {", t.Name)
|
||||
name := capitalize(t.Name)
|
||||
pf("\nexport class %s {", name)
|
||||
defer pf("}")
|
||||
|
||||
for i := 0; i < t.Type.NumField(); i++ {
|
||||
@ -165,7 +166,7 @@ func (types *Types) GenerateTypescriptDefinitions() string {
|
||||
if len(attributes) == 0 || attributes[0] == "" {
|
||||
pathParts := strings.Split(t.Type.PkgPath(), "/")
|
||||
pkg := pathParts[len(pathParts)-1]
|
||||
panic(fmt.Sprintf("(%s.%s).%s missing json declaration", pkg, t.Name, field.Name))
|
||||
panic(fmt.Sprintf("(%s.%s).%s missing json declaration", pkg, name, field.Name))
|
||||
}
|
||||
|
||||
jsonField := attributes[0]
|
||||
@ -206,7 +207,12 @@ func (types *Types) GenerateTypescriptDefinitions() string {
|
||||
if !ok {
|
||||
panic("BUG: the element types of an Slice or Array isn't in the all types map")
|
||||
}
|
||||
pf("\nexport type %s = Array<%s>", t.Name, elemTypeName)
|
||||
pf(
|
||||
"\nexport type %s = Array<%s>",
|
||||
TypescriptTypeName(
|
||||
typeCustomName{Type: t.Type, name: t.Name}),
|
||||
TypescriptTypeName(typeCustomName{Type: t.Type.Elem(), name: elemTypeName}),
|
||||
)
|
||||
}
|
||||
|
||||
return out.String()
|
||||
@ -245,7 +251,7 @@ func TypescriptTypeName(t reflect.Type) string {
|
||||
return TypescriptTypeName(t.Elem())
|
||||
case reflect.Array, reflect.Slice:
|
||||
if t.Name() != "" {
|
||||
return t.Name()
|
||||
return capitalize(t.Name())
|
||||
}
|
||||
|
||||
// []byte ([]uint8) is marshaled as a base64 string
|
||||
@ -266,7 +272,7 @@ func TypescriptTypeName(t reflect.Type) string {
|
||||
case reflect.Bool:
|
||||
return "boolean"
|
||||
case reflect.Struct:
|
||||
return t.Name()
|
||||
return capitalize(t.Name())
|
||||
default:
|
||||
panic(fmt.Sprintf(`unhandled type. Type="%+v"`, t))
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ export class UpsertProjectInfo {
|
||||
createdAt: Time;
|
||||
}
|
||||
|
||||
export class projectsHttpApiV0 {
|
||||
export class ProjectsHttpApiV0 {
|
||||
private readonly http: HttpClient = new HttpClient();
|
||||
private readonly ROOT_PATH: string = '/api/v0/projects';
|
||||
|
||||
@ -184,7 +184,7 @@ export class projectsHttpApiV0 {
|
||||
}
|
||||
}
|
||||
|
||||
export class apikeysHttpApiV0 {
|
||||
export class ApikeysHttpApiV0 {
|
||||
private readonly http: HttpClient = new HttpClient();
|
||||
private readonly ROOT_PATH: string = '/api/v0/apikeys';
|
||||
|
||||
@ -209,7 +209,7 @@ export class apikeysHttpApiV0 {
|
||||
}
|
||||
}
|
||||
|
||||
export class usersHttpApiV0 {
|
||||
export class UsersHttpApiV0 {
|
||||
private readonly http: HttpClient = new HttpClient();
|
||||
private readonly ROOT_PATH: string = '/api/v0/users';
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user