Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 1 addition & 24 deletions plugins/typescript/src/core/schemaToEnumDeclaration.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,10 @@
import { pascal } from "case";
import { SchemaObject } from "openapi3-ts/oas30";
import ts, { factory as f } from "typescript";
import { isValidIdentifier } from "tsutils";
import { convertNumberToWord } from "../utils/getEnumProperties";
import { Context, getJSDocComment } from "./schemaToTypeAliasDeclaration";

/**
* Function to check if a string is a valid TypeScript identifier
*
* @param name Name to check
*/
function isValidIdentifier(name: string): boolean {
if (name.length === 0) {
return false;
}

const firstChar = name.charCodeAt(0);
if (!ts.isIdentifierStart(firstChar, ts.ScriptTarget.Latest)) {
return false;
}

for (let i = 1; i < name.length; i++) {
if (!ts.isIdentifierPart(name.charCodeAt(i), ts.ScriptTarget.Latest)) {
return false;
}
}

return true;
}

/**
* Add Enum support when transforming an OpenAPI Schema Object to Typescript Nodes.
*
Expand Down
24 changes: 24 additions & 0 deletions plugins/typescript/src/core/schemaToTypeAliasDeclaration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -946,6 +946,30 @@ describe("schemaToTypeAliasDeclaration", () => {
`);
});

it("should generate valid identifier from number name", () => {
const schema: SchemaObject = {};

expect(printSchema(schema, "200")).toMatchInlineSnapshot(`
"export type _200 = void;"
`);
});
Comment on lines +952 to +955
Copy link
Owner

Choose a reason for hiding this comment

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

For the case where it’s only numbers, we could use this

export const convertNumberToWord = (n: number): string => {


it("should generate valid identifier from symbol name", () => {
const schema: SchemaObject = {};

expect(printSchema(schema, "-")).toMatchInlineSnapshot(`
"export type _ = void;"
`);
});

it("should generate valid identifier from invalid name", () => {
const schema: SchemaObject = {};

expect(printSchema(schema, "🙂")).toMatchInlineSnapshot(`
"export type _ = void;"
`);
});

it("should generate a `never` if the combined type is broken", () => {
const schema: SchemaObject = {
allOf: [{ type: "string" }, { type: "number" }],
Expand Down
25 changes: 19 additions & 6 deletions plugins/typescript/src/core/schemaToTypeAliasDeclaration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
} from "openapi3-ts/oas30";
import { singular } from "pluralize";
import { isValidIdentifier } from "tsutils";
import ts, { factory as f } from "typescript";
import ts, { factory as f, isIdentifierStart } from "typescript";
import { getReferenceSchema } from "./getReference";

type RemoveIndex<T> = {
Expand Down Expand Up @@ -56,11 +56,24 @@ export const schemaToTypeAliasDeclaration = (
const jsDocNode = isSchemaObject(schema)
? getJSDocComment(schema, context)
: undefined;

let identifier = pascal(name);

// If the identifier does not start with a valid character, prefix it with an underscore.
if (!isIdentifierStart(identifier.charCodeAt(0), ts.ScriptTarget.Latest)) {
identifier = `_${identifier}`;
}

// If the identifier is still not valid, remove invalid characters.
if (!isValidIdentifier(identifier)) {
identifier = identifier.replace(/[^a-zA-Z0-9_]/g, "");
}

const declarationNode = f.createTypeAliasDeclaration(
[f.createModifier(ts.SyntaxKind.ExportKeyword)],
pascal(name),
identifier,
undefined,
getType(schema, context, name)
getType(schema, context, identifier)
);

return jsDocNode ? [jsDocNode, declarationNode] : [declarationNode];
Expand Down Expand Up @@ -89,10 +102,10 @@ export const getType = (

let refNode: ts.TypeNode = f.createTypeReferenceNode(
namespace === context.currentComponent
? f.createIdentifier(pascal(name))
? f.createIdentifier(name)
: f.createQualifiedName(
f.createIdentifier(pascal(namespace)),
f.createIdentifier(pascal(name))
f.createIdentifier(name)
)
);

Expand Down Expand Up @@ -173,7 +186,7 @@ export const getType = (

if (schema.enum) {
if (isNodeEnum) {
return f.createTypeReferenceNode(f.createIdentifier(pascal(name || "")));
return f.createTypeReferenceNode(f.createIdentifier(name || ""));
}

const unionTypes = f.createUnionTypeNode([
Expand Down