Skip to content

Commit

Permalink
refactor: get rid of ReadonlyDeep type (#3201)
Browse files Browse the repository at this point in the history
  • Loading branch information
Lodin authored Feb 4, 2025
1 parent e238c32 commit d8473d8
Show file tree
Hide file tree
Showing 12 changed files with 33 additions and 47 deletions.
3 changes: 1 addition & 2 deletions packages/ts/generator-core/src/Generator.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import SwaggerParser from '@apidevtools/swagger-parser';
import type LoggerFactory from '@vaadin/hilla-generator-utils/LoggerFactory.js';
import type { OpenAPIV3 } from 'openapi-types';
import type { ReadonlyDeep } from 'type-fest';
import ts from 'typescript';
import type { PluginConstructor } from './Plugin.js';
import PluginManager from './PluginManager.js';
Expand All @@ -28,7 +27,7 @@ export default class Generator {

async process(input: string): Promise<readonly File[]> {
this.#logger.global.debug('Processing OpenAPI');
const api = (await this.#parser.bundle(JSON.parse(input))) as ReadonlyDeep<OpenAPIV3.Document>;
const api = (await this.#parser.bundle(JSON.parse(input))) as OpenAPIV3.Document;

const storage: SharedStorage = {
api,
Expand Down
3 changes: 1 addition & 2 deletions packages/ts/generator-core/src/ReferenceResolver.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import type SwaggerParser from '@apidevtools/swagger-parser';
import type { OpenAPIV3 } from 'openapi-types';
import type { ReadonlyDeep } from 'type-fest';

export default class ReferenceResolver {
readonly #parser: SwaggerParser;
Expand All @@ -9,7 +8,7 @@ export default class ReferenceResolver {
this.#parser = parser;
}

resolve<T extends ReadonlyDeep<object>>(obj: ReadonlyDeep<OpenAPIV3.ReferenceObject> | T): T {
resolve<T extends object>(obj: OpenAPIV3.ReferenceObject | T): T {
return '$ref' in obj ? this.#parser.$refs.get(obj.$ref) : obj;
}
}
13 changes: 6 additions & 7 deletions packages/ts/generator-core/src/Schema.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import type { OpenAPIV3 } from 'openapi-types';
import type { ReadonlyDeep, Simplify } from 'type-fest';

export type Nullified<T, K extends keyof T> = T & Record<K, undefined>;

export type ReferenceSchema = ReadonlyDeep<OpenAPIV3.ReferenceObject>;
export type ArraySchema = ReadonlyDeep<OpenAPIV3.ArraySchemaObject>;
export type NonArraySchema = ReadonlyDeep<OpenAPIV3.NonArraySchemaObject>;
export type ReferenceSchema = OpenAPIV3.ReferenceObject;
export type ArraySchema = OpenAPIV3.ArraySchemaObject;
export type NonArraySchema = OpenAPIV3.NonArraySchemaObject;
export type RegularSchema = ArraySchema | NonArraySchema;

export type NullableSchema = Readonly<Required<Pick<RegularSchema, 'nullable'>>> & RegularSchema;
Expand All @@ -21,7 +20,7 @@ export type ComposedSchema =
| OneOfRuleComposedSchema;

export type NonComposedRegularSchema = Readonly<Nullified<RegularSchema, 'allOf' | 'anyOf' | 'oneOf'>> & RegularSchema;
export type NonComposedSchema = Simplify<NonComposedRegularSchema | ReferenceSchema>;
export type NonComposedSchema = NonComposedRegularSchema | ReferenceSchema;

export type BooleanSchema = NonComposedRegularSchema & Readonly<{ type: 'boolean' }>;
export type IntegerSchema = NonComposedRegularSchema & Readonly<{ type: 'integer' }>;
Expand All @@ -34,7 +33,7 @@ export type EmptyObjectSchema = ObjectSchema & Readonly<Nullified<ObjectSchema,
export type NonEmptyObjectSchema = ObjectSchema & Readonly<Required<Pick<ObjectSchema, 'properties'>>>;
export type MapSchema = EmptyObjectSchema & Readonly<Required<Pick<ObjectSchema, 'additionalProperties'>>>;

export type Schema = ReadonlyDeep<ReferenceSchema | RegularSchema>;
export type Schema = ReferenceSchema | RegularSchema;

export function isReferenceSchema(schema: Schema): schema is ReferenceSchema {
return '$ref' in schema;
Expand Down Expand Up @@ -152,7 +151,7 @@ export function convertReferenceSchemaToPath(schema: ReferenceSchema): string {
}

export function resolveReference(
schemas: ReadonlyDeep<OpenAPIV3.ComponentsObject>['schemas'],
schemas: OpenAPIV3.ComponentsObject['schemas'],
{ $ref }: ReferenceSchema,
): Schema | undefined {
if (schemas) {
Expand Down
3 changes: 1 addition & 2 deletions packages/ts/generator-core/src/SharedStorage.d.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
import type { $Refs } from '@apidevtools/swagger-parser';
import type { OpenAPIV3 } from 'openapi-types';
import type { ReadonlyDeep } from 'type-fest';
import type { SourceFile, TypeNode } from 'typescript';

export type TransferTypeMaker = (typeArguments: readonly TypeNode[] | undefined) => TypeNode;

export type TransferTypes = Map<string, TransferTypeMaker>;

export type SharedStorage = Readonly<{
api: ReadonlyDeep<OpenAPIV3.Document>;
api: OpenAPIV3.Document;
apiRefs: $Refs;
outputDir?: string;
pluginStorage: Map<string, unknown>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@ import ClientPlugin from '@vaadin/hilla-generator-plugin-client';
import type DependencyManager from '@vaadin/hilla-generator-utils/dependencies/DependencyManager.js';
import equal from 'fast-deep-equal';
import { OpenAPIV3 } from 'openapi-types';
import type { ReadonlyDeep } from 'type-fest';
import ts, { type Expression, type Statement, type TypeNode } from 'typescript';
import EndpointMethodRequestBodyProcessor from './EndpointMethodRequestBodyProcessor.js';
import EndpointMethodResponseProcessor from './EndpointMethodResponseProcessor.js';

export type EndpointMethodOperation = ReadonlyDeep<OpenAPIV3.OperationObject>;
export type EndpointMethodOperation = OpenAPIV3.OperationObject;

export default abstract class EndpointMethodOperationProcessor {
// eslint-disable-next-line @typescript-eslint/max-params
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,11 @@ import {
import type { TransferTypes } from '@vaadin/hilla-generator-core/SharedStorage.js';
import type DependencyManager from '@vaadin/hilla-generator-utils/dependencies/DependencyManager.js';
import type { OpenAPIV3 } from 'openapi-types';
import type { ReadonlyDeep } from 'type-fest';
import ts, { type Identifier, type ObjectLiteralExpression, type ParameterDeclaration } from 'typescript';
import TypeSchemaProcessor from './TypeSchemaProcessor.js';
import { defaultMediaType } from './utils.js';

export type EndpointMethodRequestBody = ReadonlyDeep<OpenAPIV3.RequestBodyObject>;
export type EndpointMethodRequestBody = OpenAPIV3.RequestBodyObject;

export type EndpointMethodRequestBodyProcessingResult = Readonly<{
parameters: readonly ParameterDeclaration[];
Expand All @@ -32,7 +31,7 @@ export default class EndpointMethodRequestBodyProcessor {
readonly #requestBody?: EndpointMethodRequestBody;

constructor(
requestBody: ReadonlyDeep<OpenAPIV3.ReferenceObject | OpenAPIV3.RequestBodyObject> | undefined,
requestBody: OpenAPIV3.ReferenceObject | OpenAPIV3.RequestBodyObject | undefined,
dependencies: DependencyManager,
transferTypes: TransferTypes,
owner: Plugin,
Expand Down Expand Up @@ -102,7 +101,7 @@ export default class EndpointMethodRequestBodyProcessor {
}

#extractParameterData(
basicSchema?: ReadonlyDeep<OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject>,
basicSchema?: OpenAPIV3.ReferenceObject | OpenAPIV3.SchemaObject,
): Array<readonly [string, Schema]> {
if (!basicSchema) {
return [];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@ import type Plugin from '@vaadin/hilla-generator-core/Plugin.js';
import type { TransferTypes } from '@vaadin/hilla-generator-core/SharedStorage.js';
import type DependencyManager from '@vaadin/hilla-generator-utils/dependencies/DependencyManager.js';
import type { OpenAPIV3 } from 'openapi-types';
import type { ReadonlyDeep } from 'type-fest';
import type { TypeNode } from 'typescript';
import TypeSchemaProcessor from './TypeSchemaProcessor.js';
import { defaultMediaType } from './utils.js';

export type EndpointMethodResponses = ReadonlyDeep<OpenAPIV3.ResponsesObject>;
export type EndpointMethodResponse = ReadonlyDeep<OpenAPIV3.ResponseObject>;
export type EndpointMethodResponses = OpenAPIV3.ResponsesObject;
export type EndpointMethodResponse = OpenAPIV3.ResponseObject;

export default class EndpointMethodResponseProcessor {
readonly #code: string;
Expand Down
12 changes: 4 additions & 8 deletions packages/ts/generator-plugin-backbone/src/EndpointProcessor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,13 @@ import createSourceFile from '@vaadin/hilla-generator-utils/createSourceFile.js'
import DependencyManager from '@vaadin/hilla-generator-utils/dependencies/DependencyManager.js';
import PathManager from '@vaadin/hilla-generator-utils/dependencies/PathManager.js';
import { OpenAPIV3 } from 'openapi-types';
import type { ReadonlyDeep } from 'type-fest';
import type { SourceFile, Statement } from 'typescript';
import EndpointMethodOperationProcessor from './EndpointMethodOperationProcessor.js';

export default class EndpointProcessor {
static async create(
name: string,
methods: Map<string, ReadonlyDeep<OpenAPIV3.PathItemObject>>,
methods: Map<string, OpenAPIV3.PathItemObject>,
storage: SharedStorage,
owner: Plugin,
): Promise<EndpointProcessor> {
Expand All @@ -26,15 +25,15 @@ export default class EndpointProcessor {

readonly #createdFilePaths = new PathManager({ extension: 'ts' });
readonly #dependencies = new DependencyManager(new PathManager({ extension: '.js' }));
readonly #methods: Map<string, ReadonlyDeep<OpenAPIV3.PathItemObject>>;
readonly #methods: Map<string, OpenAPIV3.PathItemObject>;
readonly #name: string;
readonly #outputDir: string | undefined;
readonly #transferTypes: TransferTypes;
readonly #owner: Plugin;

private constructor(
name: string,
methods: Map<string, ReadonlyDeep<OpenAPIV3.PathItemObject>>,
methods: Map<string, OpenAPIV3.PathItemObject>,
storage: SharedStorage,
owner: Plugin,
) {
Expand All @@ -60,10 +59,7 @@ export default class EndpointProcessor {
);
}

async #processMethod(
method: string,
pathItem: ReadonlyDeep<OpenAPIV3.PathItemObject>,
): Promise<readonly Statement[]> {
async #processMethod(method: string, pathItem: OpenAPIV3.PathItemObject): Promise<readonly Statement[]> {
this.#owner.logger.debug(`Processing endpoint method: ${this.#name}.${method}`);

return (
Expand Down
5 changes: 2 additions & 3 deletions packages/ts/generator-plugin-backbone/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import Plugin from '@vaadin/hilla-generator-core/Plugin.js';
import type { SharedStorage } from '@vaadin/hilla-generator-core/SharedStorage.js';
import type { OpenAPIV3 } from 'openapi-types';
import type { ReadonlyDeep } from 'type-fest';
import type { SourceFile } from 'typescript';
import EndpointProcessor from './EndpointProcessor.js';
import { EntityProcessor } from './EntityProcessor.js';
Expand Down Expand Up @@ -33,14 +32,14 @@ export default class BackbonePlugin extends Plugin {

async #processEndpoints(storage: SharedStorage): Promise<readonly SourceFile[]> {
this.logger.debug('Processing endpoints');
const endpoints = new Map<string, Map<string, ReadonlyDeep<OpenAPIV3.PathItemObject>>>();
const endpoints = new Map<string, Map<string, OpenAPIV3.PathItemObject>>();

Object.entries(storage.api.paths)
.filter(([, pathItem]) => !!pathItem)
.forEach(([path, pathItem]) => {
const [, endpointName, endpointMethodName] = path.split('/');

let methods: Map<string, ReadonlyDeep<OpenAPIV3.PathItemObject>>;
let methods: Map<string, OpenAPIV3.PathItemObject>;

if (endpoints.has(endpointName)) {
methods = endpoints.get(endpointName)!;
Expand Down
3 changes: 1 addition & 2 deletions packages/ts/generator-plugin-model/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import Plugin from '@vaadin/hilla-generator-core/Plugin.js';
import type { SharedStorage } from '@vaadin/hilla-generator-core/SharedStorage.js';
import type { OpenAPIV3 } from 'openapi-types';
import type { ReadonlyDeep } from 'type-fest';
import type { SourceFile } from 'typescript';
import { EntityModelProcessor } from './EntityModelProcessor.js';
import type { Context } from './utils.js';
Expand All @@ -27,7 +26,7 @@ export default class ModelPlugin extends Plugin {
storage.pluginStorage.set(this.constructor.MODEL_PLUGIN_FILE_TAGS, this.#tags);
}

#processEntities(schemas: ReadonlyDeep<OpenAPIV3.ComponentsObject>['schemas'] | undefined): readonly SourceFile[] {
#processEntities(schemas: OpenAPIV3.ComponentsObject['schemas'] | undefined): readonly SourceFile[] {
this.logger.debug('Processing entities');

if (!schemas) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ import ts, { type SourceFile } from 'typescript';
export class SubTypesProcessor {
readonly #typeName: string;
readonly #source: SourceFile;
readonly #oneOf: ReferenceSchema[];
readonly #dependencies;
readonly #oneOf: readonly ReferenceSchema[];
readonly #dependencies: DependencyManager;

constructor(typeName: string, source: SourceFile, oneOf: ReferenceSchema[]) {
constructor(typeName: string, source: SourceFile, oneOf: readonly ReferenceSchema[]) {
this.#typeName = typeName;
this.#source = source;
this.#oneOf = oneOf;
Expand Down
17 changes: 8 additions & 9 deletions packages/ts/generator-plugin-subtypes/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import Plugin from '@vaadin/hilla-generator-core/Plugin.js';
import { convertFullyQualifiedNameToRelativePath } from '@vaadin/hilla-generator-core/Schema.js';
import { isReferenceSchema, convertFullyQualifiedNameToRelativePath } from '@vaadin/hilla-generator-core/Schema.js';
import type { SharedStorage } from '@vaadin/hilla-generator-core/SharedStorage.js';
import type { OpenAPIV3 } from 'openapi-types';
import { ModelFixProcessor } from './ModelFixProcessor.js';
import { SubTypesProcessor } from './SubTypesProcessor.js';
import { TypeFixProcessor } from './TypeFixProcessor.js';
Expand All @@ -25,19 +24,19 @@ export default class SubTypesPlugin extends Plugin {

Object.entries(components).forEach(([baseKey, baseComponent]) => {
// search for components with oneOf: those are union types
if ('oneOf' in baseComponent && Array.isArray(baseComponent.oneOf)) {
if (
'oneOf' in baseComponent &&
Array.isArray(baseComponent.oneOf) &&
baseComponent.oneOf.every((schema) => isReferenceSchema(schema))
) {
const fn = `${convertFullyQualifiedNameToRelativePath(baseKey)}.ts`;
const source = sources.find(({ fileName }) => fileName === fn)!;
// replace the (empty) source with a newly-generated one
const newSource = new SubTypesProcessor(
baseKey,
source,
baseComponent.oneOf as OpenAPIV3.ReferenceObject[],
).process();
const newSource = new SubTypesProcessor(baseKey, source, baseComponent.oneOf).process();
sources.splice(sources.indexOf(source), 1, newSource);

// mentioned types in the oneOf need to be fixed as well
(baseComponent.oneOf as OpenAPIV3.ReferenceObject[]).forEach((schema) => {
baseComponent.oneOf.forEach((schema) => {
if ('$ref' in schema) {
const path = schema.$ref;
Object.entries(components).forEach(([subKey, subComponent]) => {
Expand Down

0 comments on commit d8473d8

Please sign in to comment.