Skip to content

Commit

Permalink
feat: experimental parser supports typescript.identifierCase option
Browse files Browse the repository at this point in the history
  • Loading branch information
mrlubos committed Nov 27, 2024
1 parent ca5f6c8 commit 34ba4d9
Show file tree
Hide file tree
Showing 155 changed files with 3,567 additions and 2,554 deletions.
5 changes: 5 additions & 0 deletions .changeset/lazy-ducks-hang.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@hey-api/openapi-ts': patch
---

fix: add typescript.identifierCase option
26 changes: 20 additions & 6 deletions packages/openapi-ts/src/generate/files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ import { compiler } from '../compiler';
import { type ImportExportItemObject, tsNodeToString } from '../compiler/utils';
import type { IRContext } from '../ir/context';
import { ensureValidTypeScriptJavaScriptIdentifier } from '../openApi';
import type { StringCase } from '../types/config';
import { reservedWordsRegExp } from '../utils/regexp';
import { stringCase } from '../utils/stringCase';
import { ensureDirSync } from './utils';

interface Identifier {
Expand Down Expand Up @@ -52,6 +54,7 @@ interface Namespaces {

export class TypeScriptFile {
private _headers: Array<string> = [];
private _identifierCase: StringCase | undefined;
private _imports = new Map<string, Map<string, ImportExportItemObject>>();
private _items: Array<ts.Node | string> = [];
private _name: string;
Expand All @@ -71,12 +74,15 @@ export class TypeScriptFile {
public constructor({
dir,
header = true,
identifierCase,
name,
}: {
dir: string;
header?: boolean;
identifierCase?: StringCase;
name: string;
}) {
this._identifierCase = identifierCase;
this._name = this._setName(name);
this._path = path.resolve(dir, this._name);

Expand Down Expand Up @@ -120,7 +126,7 @@ export class TypeScriptFile {
public identifier({
namespace,
...args
}: Omit<EnsureUniqueIdentifierData, 'namespace'> & {
}: Omit<EnsureUniqueIdentifierData, 'case' | 'namespace'> & {
namespace: keyof Namespaces;
}): Identifier {
let validNameTransformer: ((name: string) => string) | undefined;
Expand All @@ -136,6 +142,7 @@ export class TypeScriptFile {
break;
}
return ensureUniqueIdentifier({
case: this._identifierCase,
namespace: this.namespaces[namespace],
validNameTransformer,
...args,
Expand Down Expand Up @@ -265,6 +272,7 @@ export class TypeScriptFile {

interface EnsureUniqueIdentifierData {
$ref: string;
case: StringCase | undefined;
count?: number;
create?: boolean;
namespace: Namespace;
Expand All @@ -273,13 +281,14 @@ interface EnsureUniqueIdentifierData {

const ensureUniqueIdentifier = ({
$ref,
case: identifierCase,
count = 1,
create = false,
namespace,
validNameTransformer,
}: EnsureUniqueIdentifierData): Identifier => {
const parts = $ref.split('/');
let name = parts[parts.length - 1] || '';
const name = parts[parts.length - 1] || '';

if (!name) {
return {
Expand All @@ -296,11 +305,13 @@ const ensureUniqueIdentifier = ({
};
}

let nameWithCasing = stringCase({ case: identifierCase, value: name });

if (count > 1) {
name = `${name}${count}`;
nameWithCasing = `${nameWithCasing}${count}`;
}

let nameValue = namespace[name];
let nameValue = namespace[nameWithCasing];
if (nameValue) {
if (nameValue.$ref === $ref) {
return {
Expand All @@ -311,6 +322,7 @@ const ensureUniqueIdentifier = ({

return ensureUniqueIdentifier({
$ref,
case: identifierCase,
count: count + 1,
create,
namespace,
Expand All @@ -327,9 +339,11 @@ const ensureUniqueIdentifier = ({

nameValue = {
$ref,
name: validNameTransformer ? validNameTransformer(name) : name,
name: validNameTransformer
? validNameTransformer(nameWithCasing)
: nameWithCasing,

Check warning on line 344 in packages/openapi-ts/src/generate/files.ts

View check run for this annotation

Codecov / codecov/patch

packages/openapi-ts/src/generate/files.ts#L344

Added line #L344 was not covered by tests
};
namespace[name] = nameValue;
namespace[nameWithCasing] = nameValue;
namespace[nameValue.$ref] = nameValue;

return {
Expand Down
18 changes: 9 additions & 9 deletions packages/openapi-ts/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,13 @@ import type { ClientPlugins } from './plugins';
import { defaultPluginConfigs } from './plugins';
import type { DefaultPluginConfigsMap, PluginNames } from './plugins/types';
import type { Client } from './types/client';
import type { ClientConfig, Config, UserConfig } from './types/config';
import type {
ClientConfig,
Config,
Formatters,
Linters,
UserConfig,
} from './types/config';
import { CLIENTS } from './types/config';
import {
isLegacyClient,
Expand All @@ -32,10 +38,7 @@ type OutputProcessor = {
/**
* Map of supported formatters
*/
const formatters: Record<
Extract<Config['output']['format'], string>,
OutputProcessor
> = {
const formatters: Record<Formatters, OutputProcessor> = {
biome: {
args: (path) => ['format', '--write', path],
command: 'biome',
Expand All @@ -57,10 +60,7 @@ const formatters: Record<
/**
* Map of supported linters
*/
const linters: Record<
Extract<Config['output']['lint'], string>,
OutputProcessor
> = {
const linters: Record<Linters, OutputProcessor> = {
biome: {
args: (path) => ['lint', '--apply', path],
command: 'biome',
Expand Down
7 changes: 6 additions & 1 deletion packages/openapi-ts/src/ir/context.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import path from 'node:path';

import { TypeScriptFile } from '../generate/files';
import type { Config } from '../types/config';
import type { Config, StringCase } from '../types/config';
import type { Files } from '../types/utils';
import { resolveRef } from '../utils/ref';
import type {
Expand All @@ -18,6 +18,10 @@ interface ContextFile {
* Unique file identifier.
*/
id: string;
/**
* Define casing for identifiers in this file.
*/
identifierCase?: StringCase;
/**
* Relative file path to the output path.
* @example
Expand Down Expand Up @@ -133,6 +137,7 @@ export class IRContext<Spec extends Record<string, any> = any> {
);
const createdFile = new TypeScriptFile({
dir: outputDir,
identifierCase: file.identifierCase,
name: `${outputParts[outputParts.length - 1]}.ts`,
});
this.files[file.id] = createdFile;
Expand Down
8 changes: 4 additions & 4 deletions packages/openapi-ts/src/openApi/common/parser/operation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,8 @@ export const operationNameFn = ({
}): string => {
if (config.plugins['@hey-api/sdk']?.operationId && operationId) {
return stringCase({
input: sanitizeNamespaceIdentifier(operationId),
style: 'camelCase',
case: 'camelCase',
value: sanitizeNamespaceIdentifier(operationId),
});
}

Expand All @@ -211,8 +211,8 @@ export const operationNameFn = ({
.replace(/[/:]/g, '-');

return stringCase({
input: `${method}-${urlWithoutPlaceholders}`,
style: 'camelCase',
case: 'camelCase',
value: `${method}-${urlWithoutPlaceholders}`,
});
};

Expand Down
8 changes: 4 additions & 4 deletions packages/openapi-ts/src/openApi/shared/utils/operation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ export const operationToId = ({
context.config.plugins['@hey-api/sdk'].operationId)
) {
return stringCase({
input: sanitizeNamespaceIdentifier(id),
style: 'camelCase',
case: 'camelCase',
value: sanitizeNamespaceIdentifier(id),
});
}

Expand All @@ -35,7 +35,7 @@ export const operationToId = ({
.replace(/[/:]/g, '-');

return stringCase({
input: `${method}-${urlWithoutPlaceholders}`,
style: 'camelCase',
value: `${method}-${urlWithoutPlaceholders}`,
çase: 'camelCase',
});
};
12 changes: 6 additions & 6 deletions packages/openapi-ts/src/plugins/@hey-api/sdk/plugin-legacy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,14 @@ export const modelResponseTransformerTypeName = (name: string) =>

export const operationDataTypeName = (name: string) =>
`${stringCase({
input: name,
style: 'PascalCase',
case: 'PascalCase',
value: name,
})}Data`;

export const operationErrorTypeName = (name: string) =>
`${stringCase({
input: name,
style: 'PascalCase',
case: 'PascalCase',
value: name,
})}Error`;

// operation response type ends with "Response", it's enough to append "Transformer"
Expand All @@ -86,8 +86,8 @@ export const operationResponseTransformerTypeName = (name: string) =>

export const operationResponseTypeName = (name: string) =>
`${stringCase({
input: name,
style: 'PascalCase',
case: 'PascalCase',
value: name,
})}Response`;

/**
Expand Down
4 changes: 2 additions & 2 deletions packages/openapi-ts/src/plugins/@hey-api/sdk/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ export const operationIrRef = ({
break;
}
return `${irRef}${stringCase({
input: id,
style: 'PascalCase',
case: 'PascalCase',
value: id,
})}${affix}`;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ export const operationTransformerIrRef = ({
break;
}
return `${irRef}${stringCase({
input: id,
// TODO: parser - do not pascalcase for functions, only for types
style: 'camelCase',
case: 'camelCase',
value: id,

Check warning on line 41 in packages/openapi-ts/src/plugins/@hey-api/transformers/plugin.ts

View check run for this annotation

Codecov / codecov/patch

packages/openapi-ts/src/plugins/@hey-api/transformers/plugin.ts#L40-L41

Added lines #L40 - L41 were not covered by tests
})}${affix}`;
};

Expand All @@ -57,8 +57,8 @@ const schemaIrRef = ({
}
const parts = $ref.split('/');
return `${parts.slice(0, parts.length - 1).join('/')}/${stringCase({
input: parts[parts.length - 1],
style: 'camelCase',
case: 'camelCase',
value: parts[parts.length - 1],

Check warning on line 61 in packages/openapi-ts/src/plugins/@hey-api/transformers/plugin.ts

View check run for this annotation

Codecov / codecov/patch

packages/openapi-ts/src/plugins/@hey-api/transformers/plugin.ts#L60-L61

Added lines #L60 - L61 were not covered by tests
})}${affix}`;
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const defaultConfig: PluginConfig<Config> = {
_handlerLegacy: handlerLegacy,
enums: false,
exportInlineEnums: false,
identifierCase: 'PascalCase',
name: '@hey-api/typescript',
output: 'types',
style: 'preserve',
Expand Down
Loading

0 comments on commit 34ba4d9

Please sign in to comment.