lukeautry / tsoa

Build OpenAPI-compliant REST APIs using TypeScript and Node
MIT License
3.33k stars 481 forks source link

Bug: TSOA does not output valid type names in Swagger definition #1559

Open KennyLindahl opened 5 months ago

KennyLindahl commented 5 months ago

Sorting

Expected Behavior

Should resolve type to acceptable name:

  1. Get the ideal name SearchableField_(typeofshopsSubFields)[ngram]_
  2. Replace unexpected characters to match ^[a-zA-Z0-9\.\-_]+$

Current Behavior

[23] build/open-api-definition.json:8:3 at #/components/schemas/SearchableField_(typeofshopsSubFields)%5Bngram%5D_

The map key in schemas "SearchableField_(typeofshopsSubFields)%5Bngram%5D_" does not match the regular expression "^[a-zA-Z0-9\.\-_]+$"

 6 |            "requestBodies": {},
 7 |            "responses": {},
 8 |            "schemas": {
 9 |                    "TotalHitsRelation": {
10 |                            "type": "string",

Error was generated by the spec-components-invalid-map-name rule.

The types looks like this:

Type gymnastics - there is pretty much no other way to make this work with TSOA):

export type ValueOf<T> = T[keyof T];

export type Source = string[] | string;

export const MARKET_IDENTIFIER = '{MARKET}';
export const searchTimeAnalyzer = {
  stemmedSynonyms: `search_analyzer_stemmed_synonyms_${MARKET_IDENTIFIER}`,
  synonyms: `search_analyzer_synonyms_${MARKET_IDENTIFIER}`,
  synonymsGeneric: `search_analyzer_synonyms_generic`,
  stemmedDelimiter: `search_analyzer_stemmed_delimiter_${MARKET_IDENTIFIER}`,
  delimiter: `search_analyzer_delimiter_${MARKET_IDENTIFIER}`,
  delimiterGeneric: `search_analyzer_delimiter_generic`,
} as const;

export type SearchTimeAnalyzer = ValueOf<typeof searchTimeAnalyzer>;

export type SearchableField<SubField extends ShopsSubFields> = {
  subField?: SubField;
  boost?: number;
  searchTimeAnalyzer?: SearchTimeAnalyzer;
};

export type SearchableFields<Field extends ShopsSearchableField> = {
  field: Field;
  boost?: number;
  phraseMatchBoost?: number;
  nestedPath?: string;
  disMaxBlock?: string;
};

export const shopsSearchableField = {
  name: 'searchableText.name',
} as const;

export const shopsSubFields = {
  edgeNgram: 'edge_ngram',
  ngram: 'ngram',
  shingles: 'shingles',
} as const;

export type ShopsSearchableField = ValueOf<typeof shopsSearchableField>;
export type ShopsSubFields = ValueOf<typeof shopsSubFields>;

export type ShopsSearchField<PossibleEmpties = undefined> =
  SearchableFields<ShopsSearchableField> & {
    searchables: {
      exact?: SearchableField<ShopsSubFields> | PossibleEmpties;
      edgeNgram?:
        | SearchableField<(typeof shopsSubFields)['edgeNgram']>
        | PossibleEmpties;
      ngram?:
        | SearchableField<(typeof shopsSubFields)['ngram']>
        | PossibleEmpties;
      shingles?:
        | SearchableField<(typeof shopsSubFields)['shingles']>
        | PossibleEmpties;
    };
  };

Possible Solution

Fix it here: https://github.com/lukeautry/tsoa/blob/master/packages/cli/src/metadataGeneration/typeResolver.ts#L1104

This should never resolve to invalid name, should always output according to acceptable pattern "^[a-zA-Z0-9\.\-_]+$"

Steps to Reproduce

See type definitions above.

Context (Environment)

Version of the library: 5.1.1 Version of NodeJS: v18.16.0 Yarn version: 1.22.19

Detailed Description

Basically we need to do type-gymnastics to resolve the types properly in TSOA. This causes it to generate bad names which is not accepted by the .

github-actions[bot] commented 5 months ago

Hello there KennyLindahl 👋

Thank you for opening your very first issue in this project.

We will try to get back to you as soon as we can.👀

github-actions[bot] commented 4 months ago

This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days

KennyLindahl commented 4 months ago

This is still an issue, please remove the stale label