diff --git a/packages/java/parser-jvm-plugin-transfertypes/pom.xml b/packages/java/parser-jvm-plugin-transfertypes/pom.xml index 1184e499a2..70e87583c9 100644 --- a/packages/java/parser-jvm-plugin-transfertypes/pom.xml +++ b/packages/java/parser-jvm-plugin-transfertypes/pom.xml @@ -2,71 +2,76 @@ - 4.0.0 + 4.0.0 - - com.vaadin - hilla-project - 24.7-SNAPSHOT - ../../../pom.xml - + + com.vaadin + hilla-project + 24.7-SNAPSHOT + ../../../pom.xml + - hilla-parser-jvm-plugin-transfertypes - Hilla JVM Parser Transfer Types Plugin - jar + hilla-parser-jvm-plugin-transfertypes + Hilla JVM Parser Transfer Types Plugin + jar - - ${project.parent.basedir} - + + ${project.parent.basedir} + - - - com.vaadin - hilla-parser-jvm-core - ${project.version} - - - org.jspecify - jspecify - - - io.github.classgraph - classgraph - - - org.junit.jupiter - junit-jupiter - test - - - com.vaadin - hilla-parser-jvm-utils - ${project.version} - - - com.vaadin - hilla-parser-jvm-plugin-backbone - ${project.version} - - - com.vaadin - hilla-runtime-plugin-transfertypes - ${project.version} - - - org.springframework.data - spring-data-commons - - - com.vaadin - hilla-parser-jvm-test-utils - ${project.version} - test - - - io.projectreactor - reactor-core - test - - + + + com.vaadin + hilla-parser-jvm-core + ${project.version} + + + org.jspecify + jspecify + + + io.github.classgraph + classgraph + + + org.junit.jupiter + junit-jupiter + test + + + com.vaadin + hilla-parser-jvm-utils + ${project.version} + + + com.vaadin + hilla-parser-jvm-plugin-backbone + ${project.version} + + + com.vaadin + hilla-runtime-plugin-transfertypes + ${project.version} + + + org.springframework.data + spring-data-commons + + + com.vaadin + hilla-parser-jvm-test-utils + ${project.version} + test + + + io.projectreactor + reactor-core + test + + + org.springframework + spring-web + test + + diff --git a/packages/java/parser-jvm-plugin-transfertypes/src/main/java/com/vaadin/hilla/parser/plugins/transfertypes/TransferTypesPlugin.java b/packages/java/parser-jvm-plugin-transfertypes/src/main/java/com/vaadin/hilla/parser/plugins/transfertypes/TransferTypesPlugin.java index 1bb43420c9..cb8ab2a9ae 100644 --- a/packages/java/parser-jvm-plugin-transfertypes/src/main/java/com/vaadin/hilla/parser/plugins/transfertypes/TransferTypesPlugin.java +++ b/packages/java/parser-jvm-plugin-transfertypes/src/main/java/com/vaadin/hilla/parser/plugins/transfertypes/TransferTypesPlugin.java @@ -12,6 +12,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; + import com.vaadin.hilla.mappedtypes.Order; import com.vaadin.hilla.mappedtypes.Pageable; import com.vaadin.hilla.mappedtypes.Sort; @@ -25,10 +26,9 @@ import com.vaadin.hilla.parser.models.ClassRefSignatureModel; import com.vaadin.hilla.parser.models.SignatureModel; import com.vaadin.hilla.parser.plugins.backbone.BackbonePlugin; -import com.vaadin.hilla.parser.plugins.backbone.nodes.CompositeTypeSignatureNode; -import com.vaadin.hilla.parser.plugins.backbone.nodes.TypeSignatureNode; import com.vaadin.hilla.parser.plugins.backbone.nodes.TypedNode; import com.vaadin.hilla.runtime.transfertypes.EndpointSubscription; +import com.vaadin.hilla.runtime.transfertypes.File; import com.vaadin.hilla.runtime.transfertypes.Flux; public final class TransferTypesPlugin @@ -48,6 +48,8 @@ public final class TransferTypesPlugin classMap.put(JsonNode.class.getName(), Object.class); classMap.put(ObjectNode.class.getName(), Object.class); classMap.put(ArrayNode.class.getName(), List.class); + classMap.put("org.springframework.web.multipart.MultipartFile", + File.class); } public TransferTypesPlugin() { diff --git a/packages/java/parser-jvm-plugin-transfertypes/src/test/java/com/vaadin/hilla/parser/plugins/transfertypes/file/Endpoint.java b/packages/java/parser-jvm-plugin-transfertypes/src/test/java/com/vaadin/hilla/parser/plugins/transfertypes/file/Endpoint.java new file mode 100644 index 0000000000..cbfd93a487 --- /dev/null +++ b/packages/java/parser-jvm-plugin-transfertypes/src/test/java/com/vaadin/hilla/parser/plugins/transfertypes/file/Endpoint.java @@ -0,0 +1,11 @@ +package com.vaadin.hilla.parser.plugins.transfertypes.file; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +public @interface Endpoint { +} diff --git a/packages/java/parser-jvm-plugin-transfertypes/src/test/java/com/vaadin/hilla/parser/plugins/transfertypes/file/MultipartFileEndpoint.java b/packages/java/parser-jvm-plugin-transfertypes/src/test/java/com/vaadin/hilla/parser/plugins/transfertypes/file/MultipartFileEndpoint.java new file mode 100644 index 0000000000..17f1a507dd --- /dev/null +++ b/packages/java/parser-jvm-plugin-transfertypes/src/test/java/com/vaadin/hilla/parser/plugins/transfertypes/file/MultipartFileEndpoint.java @@ -0,0 +1,9 @@ +package com.vaadin.hilla.parser.plugins.transfertypes.file; + +import org.springframework.web.multipart.MultipartFile; + +@Endpoint +public class MultipartFileEndpoint { + public void uploadFile(MultipartFile file) { + } +} diff --git a/packages/java/parser-jvm-plugin-transfertypes/src/test/java/com/vaadin/hilla/parser/plugins/transfertypes/file/MultipartFileTest.java b/packages/java/parser-jvm-plugin-transfertypes/src/test/java/com/vaadin/hilla/parser/plugins/transfertypes/file/MultipartFileTest.java new file mode 100644 index 0000000000..07f119ada7 --- /dev/null +++ b/packages/java/parser-jvm-plugin-transfertypes/src/test/java/com/vaadin/hilla/parser/plugins/transfertypes/file/MultipartFileTest.java @@ -0,0 +1,30 @@ +package com.vaadin.hilla.parser.plugins.transfertypes.file; + +import java.io.IOException; +import java.net.URISyntaxException; +import java.util.List; +import java.util.Set; + +import org.junit.jupiter.api.Test; + +import com.vaadin.hilla.parser.core.Parser; +import com.vaadin.hilla.parser.plugins.backbone.BackbonePlugin; +import com.vaadin.hilla.parser.plugins.transfertypes.TransferTypesPlugin; +import com.vaadin.hilla.parser.plugins.transfertypes.test.helpers.TestHelper; + +public class MultipartFileTest { + private final TestHelper helper = new TestHelper(getClass()); + + @Test + public void should_ReplaceMultipartFileClassWithLocalFileClass() + throws IOException, URISyntaxException { + var openAPI = new Parser() + .classPath(Set.of(helper.getTargetDir().toString())) + .endpointAnnotations(List.of(Endpoint.class)) + .addPlugin(new BackbonePlugin()) + .addPlugin(new TransferTypesPlugin()) + .execute(List.of(MultipartFileEndpoint.class)); + + helper.executeParserWithConfig(openAPI); + } +} diff --git a/packages/java/parser-jvm-plugin-transfertypes/src/test/resources/com/vaadin/hilla/parser/plugins/transfertypes/file/openapi.json b/packages/java/parser-jvm-plugin-transfertypes/src/test/resources/com/vaadin/hilla/parser/plugins/transfertypes/file/openapi.json new file mode 100644 index 0000000000..8fb7e41a4f --- /dev/null +++ b/packages/java/parser-jvm-plugin-transfertypes/src/test/resources/com/vaadin/hilla/parser/plugins/transfertypes/file/openapi.json @@ -0,0 +1,60 @@ +{ + "openapi" : "3.0.1", + "info" : { + "title" : "Hilla Application", + "version" : "1.0.0" + }, + "servers" : [ + { + "url" : "http://localhost:8080/connect", + "description" : "Hilla Backend" + } + ], + "tags" : [ + { + "name" : "MultipartFileEndpoint", + "x-class-name" : "com.vaadin.hilla.parser.plugins.transfertypes.file.MultipartFileEndpoint" + } + ], + "paths" : { + "/MultipartFileEndpoint/uploadFile" : { + "post" : { + "tags" : [ + "MultipartFileEndpoint" + ], + "operationId" : "MultipartFileEndpoint_uploadFile_POST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "type" : "object", + "properties" : { + "file" : { + "nullable" : true, + "anyOf" : [ + { + "$ref" : "#/components/schemas/com.vaadin.hilla.runtime.transfertypes.File" + } + ] + } + } + } + } + } + }, + "responses" : { + "200" : { + "description" : "" + } + } + } + } + }, + "components" : { + "schemas" : { + "com.vaadin.hilla.runtime.transfertypes.File" : { + "type" : "object" + } + } + } +} diff --git a/packages/java/runtime-plugin-transfertypes/src/main/java/com/vaadin/hilla/runtime/transfertypes/File.java b/packages/java/runtime-plugin-transfertypes/src/main/java/com/vaadin/hilla/runtime/transfertypes/File.java new file mode 100644 index 0000000000..9bdf18ba66 --- /dev/null +++ b/packages/java/runtime-plugin-transfertypes/src/main/java/com/vaadin/hilla/runtime/transfertypes/File.java @@ -0,0 +1,4 @@ +package com.vaadin.hilla.runtime.transfertypes; + +public record File() { +} diff --git a/packages/ts/generator-cli/src/GeneratorIO.ts b/packages/ts/generator-cli/src/GeneratorIO.ts index a866776cdb..fdab9afe32 100644 --- a/packages/ts/generator-cli/src/GeneratorIO.ts +++ b/packages/ts/generator-cli/src/GeneratorIO.ts @@ -3,7 +3,6 @@ import { access, mkdir, readFile, rm, writeFile } from 'node:fs/promises'; import { createRequire } from 'node:module'; import { dirname, isAbsolute, join, resolve } from 'node:path'; import { pathToFileURL } from 'node:url'; -import type File from '@vaadin/hilla-generator-core/File.js'; import Plugin, { type PluginConstructor } from '@vaadin/hilla-generator-core/Plugin.js'; import type LoggerFactory from '@vaadin/hilla-generator-utils/LoggerFactory.js'; import GeneratorIOException from './GeneratorIOException.js'; diff --git a/packages/ts/generator-cli/test/GeneratorIO.spec.ts b/packages/ts/generator-cli/test/GeneratorIO.spec.ts index 06806e9ec8..fb704b473e 100644 --- a/packages/ts/generator-cli/test/GeneratorIO.spec.ts +++ b/packages/ts/generator-cli/test/GeneratorIO.spec.ts @@ -2,7 +2,6 @@ import { statSync } from 'node:fs'; import { chmod, mkdtemp, rm, writeFile } from 'node:fs/promises'; import { tmpdir } from 'node:os'; import { join } from 'node:path'; -import File from '@vaadin/hilla-generator-core/File.js'; import LoggerFactory from '@vaadin/hilla-generator-utils/LoggerFactory.js'; import chaiAsPromised from 'chai-as-promised'; import { expect, chai, describe, it, beforeEach, afterEach } from 'vitest'; diff --git a/packages/ts/generator-core/package.json b/packages/ts/generator-core/package.json index 1ff722f069..b9ad2c8590 100644 --- a/packages/ts/generator-core/package.json +++ b/packages/ts/generator-core/package.json @@ -44,9 +44,6 @@ }, "./SharedStorage.js": { "types": "./SharedStorage.d.ts" - }, - "./utils.js": { - "default": "./utils.js" } }, "repository": { diff --git a/packages/ts/generator-core/src/File.ts b/packages/ts/generator-core/src/File.ts deleted file mode 100644 index 5143491e5b..0000000000 --- a/packages/ts/generator-core/src/File.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Blob, type BlobOptions } from 'node:buffer'; -import type { BinaryLike } from 'node:crypto'; - -export type FileOptions = Readonly< - BlobOptions & { - lastModified?: number; - } ->; - -export default class File extends Blob { - readonly #name: string; - - constructor(fileBits: Array, fileName: string, options?: FileOptions) { - super(fileBits, options); - this.#name = fileName; - } - - get name(): string { - return this.#name; - } -} diff --git a/packages/ts/generator-core/src/Generator.ts b/packages/ts/generator-core/src/Generator.ts index dd99cfa8d5..971bd5ea13 100644 --- a/packages/ts/generator-core/src/Generator.ts +++ b/packages/ts/generator-core/src/Generator.ts @@ -3,11 +3,10 @@ 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 File from './File.js'; import type { PluginConstructor } from './Plugin.js'; import PluginManager from './PluginManager.js'; import ReferenceResolver from './ReferenceResolver.js'; -import type SharedStorage from './SharedStorage.js'; +import type { SharedStorage } from './SharedStorage.js'; export type GeneratorContext = Readonly<{ logger: LoggerFactory; @@ -37,6 +36,7 @@ export default class Generator { outputDir: this.#outputDir, pluginStorage: new Map(), sources: [], + transferTypes: new Map(), }; this.#logger.global.debug('Executing plugins'); diff --git a/packages/ts/generator-core/src/Plugin.ts b/packages/ts/generator-core/src/Plugin.ts index eabfab89a4..6e1e13de78 100644 --- a/packages/ts/generator-core/src/Plugin.ts +++ b/packages/ts/generator-core/src/Plugin.ts @@ -2,7 +2,7 @@ import type LoggerFactory from '@vaadin/hilla-generator-utils/LoggerFactory.js'; import type { Logger } from '@vaadin/hilla-generator-utils/LoggerFactory.js'; import type { Constructor } from 'type-fest'; import type ReferenceResolver from './ReferenceResolver.js'; -import type SharedStorage from './SharedStorage.js'; +import type { SharedStorage } from './SharedStorage.js'; export default abstract class Plugin { readonly resolver: ReferenceResolver; @@ -19,7 +19,7 @@ export default abstract class Plugin { abstract get path(): string; - abstract execute(storage: SharedStorage): Promise; + abstract execute(storage: SharedStorage): Promise | void; } export type PluginConstructor = Constructor>; diff --git a/packages/ts/generator-core/src/PluginManager.ts b/packages/ts/generator-core/src/PluginManager.ts index 59f468f652..644e0c25a6 100644 --- a/packages/ts/generator-core/src/PluginManager.ts +++ b/packages/ts/generator-core/src/PluginManager.ts @@ -2,13 +2,14 @@ import type LoggerFactory from '@vaadin/hilla-generator-utils/LoggerFactory.js'; import type Plugin from './Plugin.js'; import type { PluginConstructor } from './Plugin.js'; import type ReferenceResolver from './ReferenceResolver.js'; -import type SharedStorage from './SharedStorage.js'; +import type { SharedStorage } from './SharedStorage.js'; export default class PluginManager { readonly #plugins: Plugin[]; constructor(plugins: readonly PluginConstructor[], resolver: ReferenceResolver, logger: LoggerFactory) { const standardPlugins = [ + 'TransferTypesPlugin', // should go before Backbone Plugin 'BackbonePlugin', 'ClientPlugin', 'BarrelPlugin', diff --git a/packages/ts/generator-core/src/Schema.ts b/packages/ts/generator-core/src/Schema.ts index e7fd41e42c..de871f4867 100644 --- a/packages/ts/generator-core/src/Schema.ts +++ b/packages/ts/generator-core/src/Schema.ts @@ -1,6 +1,7 @@ import type { OpenAPIV3 } from 'openapi-types'; -import type { ReadonlyDeep } from 'type-fest'; -import { convertFullyQualifiedNameToRelativePath, simplifyFullyQualifiedName, type Nullified } from './utils.js'; +import type { ReadonlyDeep, Simplify } from 'type-fest'; + +export type Nullified = T & Record; export type ReferenceSchema = ReadonlyDeep; export type ArraySchema = ReadonlyDeep; @@ -20,7 +21,7 @@ export type ComposedSchema = | OneOfRuleComposedSchema; export type NonComposedRegularSchema = Readonly> & RegularSchema; -export type NonComposedSchema = NonComposedRegularSchema | ReferenceSchema; +export type NonComposedSchema = Simplify; export type BooleanSchema = NonComposedRegularSchema & Readonly<{ type: 'boolean' }>; export type IntegerSchema = NonComposedRegularSchema & Readonly<{ type: 'integer' }>; @@ -33,7 +34,7 @@ export type EmptyObjectSchema = ObjectSchema & Readonly>>; export type MapSchema = EmptyObjectSchema & Readonly>>; -export type Schema = ReferenceSchema | RegularSchema; +export type Schema = ReadonlyDeep; export function isReferenceSchema(schema: Schema): schema is ReferenceSchema { return '$ref' in schema; @@ -128,14 +129,26 @@ export function isMapSchema(schema: Schema): schema is MapSchema { return isEmptyObject(schema) && !!schema.additionalProperties; } +export function simplifyFullyQualifiedName(name: string): string { + return name.substring(name.lastIndexOf(name.includes('$') ? '$' : '.') + 1, name.length); +} + export function convertReferenceSchemaToSpecifier({ $ref }: ReferenceSchema): string { return simplifyFullyQualifiedName($ref); } const COMPONENTS_SCHEMAS_REF_LENGTH = '#/components/schemas/'.length; -export function convertReferenceSchemaToPath({ $ref }: ReferenceSchema): string { - return convertFullyQualifiedNameToRelativePath($ref.substring(COMPONENTS_SCHEMAS_REF_LENGTH)); +export function convertReferenceSchemaToFullyQualifiedName({ $ref }: ReferenceSchema): string { + return $ref.substring(COMPONENTS_SCHEMAS_REF_LENGTH); +} + +export function convertFullyQualifiedNameToRelativePath(name: string): string { + return name.replace(/[$.]/gu, '/'); +} + +export function convertReferenceSchemaToPath(schema: ReferenceSchema): string { + return convertFullyQualifiedNameToRelativePath(convertReferenceSchemaToFullyQualifiedName(schema)); } export function resolveReference( diff --git a/packages/ts/generator-core/src/SharedStorage.d.ts b/packages/ts/generator-core/src/SharedStorage.d.ts index 2280afd82f..538c24cfdb 100644 --- a/packages/ts/generator-core/src/SharedStorage.d.ts +++ b/packages/ts/generator-core/src/SharedStorage.d.ts @@ -1,14 +1,17 @@ import type { $Refs } from '@apidevtools/swagger-parser'; import type { OpenAPIV3 } from 'openapi-types'; import type { ReadonlyDeep } from 'type-fest'; -import type { SourceFile } from 'typescript'; +import type { SourceFile, TypeNode } from 'typescript'; -type SharedStorage = Readonly<{ +export type TransferTypeMaker = (typeArguments: readonly TypeNode[] | undefined) => TypeNode; + +export type TransferTypes = Map; + +export type SharedStorage = Readonly<{ api: ReadonlyDeep; apiRefs: $Refs; - sources: SourceFile[]; - pluginStorage: Map; outputDir?: string; + pluginStorage: Map; + sources: SourceFile[]; + transferTypes: TransferTypes; }>; - -export default SharedStorage; diff --git a/packages/ts/generator-core/src/utils.ts b/packages/ts/generator-core/src/utils.ts deleted file mode 100644 index b2cc01dc79..0000000000 --- a/packages/ts/generator-core/src/utils.ts +++ /dev/null @@ -1,11 +0,0 @@ -export type Nullified = T & Record; - -export function simplifyFullyQualifiedName(name: string): string { - return name.substring(name.lastIndexOf(name.includes('$') ? '$' : '.') + 1, name.length); -} - -const QUALIFIED_NAME_DELIMITER = /[$.]/gu; - -export function convertFullyQualifiedNameToRelativePath(name: string): string { - return name.replace(QUALIFIED_NAME_DELIMITER, '/'); -} diff --git a/packages/ts/generator-plugin-backbone/src/EndpointMethodOperationProcessor.ts b/packages/ts/generator-plugin-backbone/src/EndpointMethodOperationProcessor.ts index 6de83c9f9d..2a31760537 100644 --- a/packages/ts/generator-plugin-backbone/src/EndpointMethodOperationProcessor.ts +++ b/packages/ts/generator-plugin-backbone/src/EndpointMethodOperationProcessor.ts @@ -1,5 +1,6 @@ /* eslint-disable max-params */ import type Plugin from '@vaadin/hilla-generator-core/Plugin.js'; +import type { TransferTypes } from '@vaadin/hilla-generator-core/SharedStorage.js'; 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'; @@ -11,9 +12,6 @@ import EndpointMethodResponseProcessor from './EndpointMethodResponseProcessor.j export type EndpointMethodOperation = ReadonlyDeep; -export const INIT_TYPE_NAME = 'EndpointRequestInit'; -export const HILLA_FRONTEND_NAME = '@vaadin/hilla-frontend'; - export default abstract class EndpointMethodOperationProcessor { // eslint-disable-next-line @typescript-eslint/max-params static createProcessor( @@ -22,6 +20,7 @@ export default abstract class EndpointMethodOperationProcessor { endpointMethodName: string, operation: EndpointMethodOperation, dependencies: DependencyManager, + transferTypes: TransferTypes, owner: Plugin, ): EndpointMethodOperationProcessor | undefined { switch (httpMethod) { @@ -32,6 +31,7 @@ export default abstract class EndpointMethodOperationProcessor { endpointMethodName, operation, dependencies, + transferTypes, owner, ); } @@ -46,6 +46,7 @@ export default abstract class EndpointMethodOperationProcessor { class EndpointMethodOperationPOSTProcessor extends EndpointMethodOperationProcessor { readonly #dependencies: DependencyManager; + readonly #transferTypes: TransferTypes; readonly #endpointMethodName: string; readonly #endpointName: string; readonly #operation: EndpointMethodOperation; @@ -57,6 +58,7 @@ class EndpointMethodOperationPOSTProcessor extends EndpointMethodOperationProces endpointMethodName: string, operation: EndpointMethodOperation, dependencies: DependencyManager, + transferTypes: TransferTypes, owner: Plugin, ) { super(); @@ -65,21 +67,18 @@ class EndpointMethodOperationPOSTProcessor extends EndpointMethodOperationProces this.#endpointName = endpointName; this.#endpointMethodName = endpointMethodName; this.#operation = operation; + this.#transferTypes = transferTypes; } async process(outputDir?: string): Promise { const { exports, imports, paths } = this.#dependencies; this.#owner.logger.debug(`${this.#endpointName}.${this.#endpointMethodName} - processing POST method`); - const initTypeIdentifier = imports.named.getIdentifier( - paths.createBareModulePath(HILLA_FRONTEND_NAME), - INIT_TYPE_NAME, - )!; const { initParam, packedParameters, parameters } = new EndpointMethodRequestBodyProcessor( this.#operation.requestBody, this.#dependencies, + this.#transferTypes, this.#owner, - initTypeIdentifier, ).process(); const methodIdentifier = exports.named.add(this.#endpointMethodName); @@ -116,7 +115,13 @@ class EndpointMethodOperationPOSTProcessor extends EndpointMethodOperationProces const responseTypes = Object.entries(this.#operation.responses) .flatMap(([code, response]) => - new EndpointMethodResponseProcessor(code, response, this.#dependencies, this.#owner).process(), + new EndpointMethodResponseProcessor( + code, + response, + this.#dependencies, + this.#transferTypes, + this.#owner, + ).process(), ) .filter((value, index, arr) => arr.findIndex((v) => equal(v, value)) === index); diff --git a/packages/ts/generator-plugin-backbone/src/EndpointMethodRequestBodyProcessor.ts b/packages/ts/generator-plugin-backbone/src/EndpointMethodRequestBodyProcessor.ts index 07c6bffe14..0113cd518f 100644 --- a/packages/ts/generator-plugin-backbone/src/EndpointMethodRequestBodyProcessor.ts +++ b/packages/ts/generator-plugin-backbone/src/EndpointMethodRequestBodyProcessor.ts @@ -5,10 +5,11 @@ import { type NonEmptyObjectSchema, type Schema, } from '@vaadin/hilla-generator-core/Schema.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 ts, { type ObjectLiteralExpression, type ParameterDeclaration } from 'typescript'; +import ts, { type Identifier, type ObjectLiteralExpression, type ParameterDeclaration } from 'typescript'; import TypeSchemaProcessor from './TypeSchemaProcessor.js'; import { defaultMediaType } from './utils.js'; @@ -17,41 +18,48 @@ export type EndpointMethodRequestBody = ReadonlyDeep; -export default class EndpointMethodRequestBodyProcessor { - static readonly #defaultInitParamName = 'init'; +const DEFAULT_INIT_PARAM_NAME = 'init'; +const INIT_TYPE_NAME = 'EndpointRequestInit'; +const HILLA_FRONTEND_NAME = '@vaadin/hilla-frontend'; +export default class EndpointMethodRequestBodyProcessor { readonly #dependencies: DependencyManager; + readonly #transferTypes: TransferTypes; readonly #owner: Plugin; readonly #requestBody?: EndpointMethodRequestBody; - readonly #initTypeIdentifier: ts.Identifier; constructor( requestBody: ReadonlyDeep | undefined, dependencies: DependencyManager, + transferTypes: TransferTypes, owner: Plugin, - initTypeIdentifier: ts.Identifier, ) { this.#owner = owner; this.#dependencies = dependencies; this.#requestBody = requestBody ? owner.resolver.resolve(requestBody) : undefined; - this.#initTypeIdentifier = initTypeIdentifier; + this.#transferTypes = transferTypes; } process(): EndpointMethodRequestBodyProcessingResult { + const { imports, paths } = this.#dependencies; + const path = paths.createBareModulePath(HILLA_FRONTEND_NAME); + const initTypeIdentifier = + imports.named.getIdentifier(path, INIT_TYPE_NAME) ?? imports.named.add(path, INIT_TYPE_NAME); + if (!this.#requestBody) { return { - initParam: ts.factory.createIdentifier(EndpointMethodRequestBodyProcessor.#defaultInitParamName), + initParam: ts.factory.createIdentifier(DEFAULT_INIT_PARAM_NAME), packedParameters: ts.factory.createObjectLiteralExpression(), parameters: [ ts.factory.createParameterDeclaration( undefined, undefined, - EndpointMethodRequestBodyProcessor.#defaultInitParamName, + DEFAULT_INIT_PARAM_NAME, ts.factory.createToken(ts.SyntaxKind.QuestionToken), - ts.factory.createTypeReferenceNode(this.#initTypeIdentifier), + ts.factory.createTypeReferenceNode(initTypeIdentifier), ), ], }; @@ -59,7 +67,7 @@ export default class EndpointMethodRequestBodyProcessor { const parameterData = this.#extractParameterData(this.#requestBody.content[defaultMediaType].schema); const parameterNames = parameterData.map(([name]) => name); - let initParamName = EndpointMethodRequestBodyProcessor.#defaultInitParamName; + let initParamName = DEFAULT_INIT_PARAM_NAME; while (parameterNames.includes(initParamName)) { initParamName = `_${initParamName}`; @@ -72,7 +80,7 @@ export default class EndpointMethodRequestBodyProcessor { ), parameters: [ ...parameterData.map(([name, schema]) => { - const nodes = new TypeSchemaProcessor(schema, this.#dependencies).process(); + const nodes = new TypeSchemaProcessor(schema, this.#dependencies, this.#transferTypes).process(); return ts.factory.createParameterDeclaration( undefined, @@ -87,7 +95,7 @@ export default class EndpointMethodRequestBodyProcessor { undefined, initParamName, ts.factory.createToken(ts.SyntaxKind.QuestionToken), - ts.factory.createTypeReferenceNode(this.#initTypeIdentifier), + ts.factory.createTypeReferenceNode(initTypeIdentifier), ), ], }; diff --git a/packages/ts/generator-plugin-backbone/src/EndpointMethodResponseProcessor.ts b/packages/ts/generator-plugin-backbone/src/EndpointMethodResponseProcessor.ts index 798b499529..23fdef2a73 100644 --- a/packages/ts/generator-plugin-backbone/src/EndpointMethodResponseProcessor.ts +++ b/packages/ts/generator-plugin-backbone/src/EndpointMethodResponseProcessor.ts @@ -1,4 +1,5 @@ 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'; @@ -12,19 +13,23 @@ export type EndpointMethodResponse = ReadonlyDeep; export default class EndpointMethodResponseProcessor { readonly #code: string; readonly #dependencies: DependencyManager; + readonly #transferTypes: TransferTypes; readonly #owner: Plugin; readonly #response: EndpointMethodResponse; + // eslint-disable-next-line @typescript-eslint/max-params constructor( code: string, response: EndpointMethodResponses[string], dependencyManager: DependencyManager, + transferTypes: TransferTypes, owner: Plugin, ) { this.#code = code; this.#owner = owner; this.#dependencies = dependencyManager; this.#response = owner.resolver.resolve(response); + this.#transferTypes = transferTypes; } process(): readonly TypeNode[] { @@ -40,6 +45,6 @@ export default class EndpointMethodResponseProcessor { #processOk(): readonly TypeNode[] { const rawSchema = this.#response.content?.[defaultMediaType]?.schema; - return rawSchema ? new TypeSchemaProcessor(rawSchema, this.#dependencies).process() : []; + return rawSchema ? new TypeSchemaProcessor(rawSchema, this.#dependencies, this.#transferTypes).process() : []; } } diff --git a/packages/ts/generator-plugin-backbone/src/EndpointProcessor.ts b/packages/ts/generator-plugin-backbone/src/EndpointProcessor.ts index da06f0a191..7661926870 100644 --- a/packages/ts/generator-plugin-backbone/src/EndpointProcessor.ts +++ b/packages/ts/generator-plugin-backbone/src/EndpointProcessor.ts @@ -1,4 +1,5 @@ import type Plugin from '@vaadin/hilla-generator-core/Plugin.js'; +import type { SharedStorage, TransferTypes } from '@vaadin/hilla-generator-core/SharedStorage.js'; import ClientPlugin from '@vaadin/hilla-generator-plugin-client'; import createSourceFile from '@vaadin/hilla-generator-utils/createSourceFile.js'; import DependencyManager from '@vaadin/hilla-generator-utils/dependencies/DependencyManager.js'; @@ -6,27 +7,20 @@ import PathManager from '@vaadin/hilla-generator-utils/dependencies/PathManager. import { OpenAPIV3 } from 'openapi-types'; import type { ReadonlyDeep } from 'type-fest'; import type { SourceFile, Statement } from 'typescript'; -import EndpointMethodOperationProcessor, { - HILLA_FRONTEND_NAME, - INIT_TYPE_NAME, -} from './EndpointMethodOperationProcessor.js'; +import EndpointMethodOperationProcessor from './EndpointMethodOperationProcessor.js'; export default class EndpointProcessor { static async create( name: string, - owner: Plugin, methods: Map>, - outputDir?: string, + storage: SharedStorage, + owner: Plugin, ): Promise { - const endpoint = new EndpointProcessor(name, owner, methods, outputDir); + const endpoint = new EndpointProcessor(name, methods, storage, owner); endpoint.#dependencies.imports.default.add( - endpoint.#dependencies.paths.createRelativePath(await ClientPlugin.getClientFileName(outputDir)), + endpoint.#dependencies.paths.createRelativePath(await ClientPlugin.getClientFileName(storage.outputDir)), 'client', ); - endpoint.#dependencies.imports.named.add( - endpoint.#dependencies.paths.createBareModulePath(HILLA_FRONTEND_NAME), - INIT_TYPE_NAME, - ); return endpoint; } @@ -35,18 +29,20 @@ export default class EndpointProcessor { readonly #methods: Map>; readonly #name: string; readonly #outputDir: string | undefined; + readonly #transferTypes: TransferTypes; readonly #owner: Plugin; private constructor( name: string, - owner: Plugin, methods: Map>, - outputDir?: string, + storage: SharedStorage, + owner: Plugin, ) { this.#name = name; this.#owner = owner; this.#methods = methods; - this.#outputDir = outputDir; + this.#outputDir = storage.outputDir; + this.#transferTypes = storage.transferTypes; } async process(): Promise { @@ -81,6 +77,7 @@ export default class EndpointProcessor { method, pathItem[httpMethod]!, this.#dependencies, + this.#transferTypes, this.#owner, )?.process(this.#outputDir), ), diff --git a/packages/ts/generator-plugin-backbone/src/EntityProcessor.ts b/packages/ts/generator-plugin-backbone/src/EntityProcessor.ts index 884bb34a95..a83ae722a9 100644 --- a/packages/ts/generator-plugin-backbone/src/EntityProcessor.ts +++ b/packages/ts/generator-plugin-backbone/src/EntityProcessor.ts @@ -14,11 +14,10 @@ import { isObjectSchema, isReferenceSchema, type ObjectSchema, -} from '@vaadin/hilla-generator-core/Schema.js'; -import { convertFullyQualifiedNameToRelativePath, simplifyFullyQualifiedName, -} from '@vaadin/hilla-generator-core/utils.js'; +} from '@vaadin/hilla-generator-core/Schema.js'; +import type { SharedStorage, TransferTypes } from '@vaadin/hilla-generator-core/SharedStorage.js'; 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'; @@ -28,6 +27,7 @@ import ts, { type SourceFile, type Statement, type TypeElement, + type TypeParameterDeclaration, } from 'typescript'; import TypeSchemaProcessor from './TypeSchemaProcessor.js'; import { findTypeParameters } from './utils.js'; @@ -38,16 +38,18 @@ export class EntityProcessor { readonly #fullyQualifiedName: string; readonly #name: string; readonly #outputPathManager = new PathManager({ extension: 'ts' }); + readonly #transferTypes: TransferTypes; readonly #owner: Plugin; readonly #path: string; - constructor(name: string, component: Schema, owner: Plugin) { + constructor(name: string, component: Schema, storage: SharedStorage, owner: Plugin) { this.#component = component; this.#owner = owner; this.#fullyQualifiedName = name; this.#name = simplifyFullyQualifiedName(name); this.#path = convertFullyQualifiedNameToRelativePath(name); this.#dependencies = new DependencyManager(new PathManager({ extension: '.js', relativeTo: dirname(this.#path) })); + this.#transferTypes = storage.transferTypes; } get #id(): Identifier { @@ -159,7 +161,7 @@ export class EntityProcessor { #processTypeElements({ properties }: ObjectSchema): readonly TypeElement[] { return Object.entries(properties ?? {}).map(([name, schema]) => { - const [type] = new TypeSchemaProcessor(schema, this.#dependencies).process(); + const [type] = new TypeSchemaProcessor(schema, this.#dependencies, this.#transferTypes).process(); return ts.factory.createPropertySignature( undefined, @@ -170,7 +172,7 @@ export class EntityProcessor { }); } - static #processTypeParameters(schema: Schema): readonly ts.TypeParameterDeclaration[] | undefined { + static #processTypeParameters(schema: Schema): readonly TypeParameterDeclaration[] | undefined { return findTypeParameters(schema) ?.map(String) .map((name) => diff --git a/packages/ts/generator-plugin-backbone/src/TypeSchemaProcessor.ts b/packages/ts/generator-plugin-backbone/src/TypeSchemaProcessor.ts index 64faf82678..e1028e75b2 100644 --- a/packages/ts/generator-plugin-backbone/src/TypeSchemaProcessor.ts +++ b/packages/ts/generator-plugin-backbone/src/TypeSchemaProcessor.ts @@ -1,6 +1,7 @@ import { type ArraySchema, - convertReferenceSchemaToPath, + convertFullyQualifiedNameToRelativePath, + convertReferenceSchemaToFullyQualifiedName, convertReferenceSchemaToSpecifier, decomposeSchema, isArraySchema, @@ -17,6 +18,7 @@ import { type ReferenceSchema, type Schema, } from '@vaadin/hilla-generator-core/Schema.js'; +import type { TransferTypeMaker } from '@vaadin/hilla-generator-core/SharedStorage.js'; import type DependencyManager from '@vaadin/hilla-generator-utils/dependencies/DependencyManager.js'; import ts, { type TypeNode } from 'typescript'; import { findTypeArguments, findTypeVariable } from './utils.js'; @@ -55,10 +57,12 @@ export default class TypeSchemaProcessor { declare ['constructor']: typeof TypeSchemaProcessor; readonly #dependencies: DependencyManager; readonly #schema: Schema; + readonly #transferTypes: Map; - constructor(schema: Schema, dependencies: DependencyManager) { + constructor(schema: Schema, dependencies: DependencyManager, transferTypes: Map) { this.#schema = schema; this.#dependencies = dependencies; + this.#transferTypes = transferTypes; } process(): readonly TypeNode[] { @@ -93,7 +97,7 @@ export default class TypeSchemaProcessor { } #processArray(schema: ArraySchema): TypeNode { - const nodes = new TypeSchemaProcessor(schema.items, this.#dependencies).process(); + const nodes = new TypeSchemaProcessor(schema.items, this.#dependencies, this.#transferTypes).process(); return ts.factory.createTypeReferenceNode('Array', [ts.factory.createUnionTypeNode(nodes)]); } @@ -102,7 +106,7 @@ export default class TypeSchemaProcessor { let valuesTypeNode: TypeNode; if (typeof valuesType !== 'boolean') { - const nodes = new TypeSchemaProcessor(valuesType, this.#dependencies).process(); + const nodes = new TypeSchemaProcessor(valuesType, this.#dependencies, this.#transferTypes).process(); valuesTypeNode = ts.factory.createUnionTypeNode(nodes); } else { valuesTypeNode = ts.factory.createKeywordTypeNode(ts.SyntaxKind.UnknownKeyword); @@ -114,18 +118,24 @@ export default class TypeSchemaProcessor { ]); } - #processTypeArguments(schema: Schema): readonly ts.TypeNode[] | undefined { + #processTypeArguments(schema: Schema): readonly TypeNode[] | undefined { // Type arguments are processed recursively return findTypeArguments(schema) - ?.allOf.map((s) => new TypeSchemaProcessor(s, this.#dependencies).process()) + ?.allOf.map((s) => new TypeSchemaProcessor(s, this.#dependencies, this.#transferTypes).process()) .map((t) => ts.factory.createUnionTypeNode(t)); } - #processReference(schema: ReferenceSchema, typeArguments: readonly ts.TypeNode[] | undefined): TypeNode { + #processReference(schema: ReferenceSchema, typeArguments: readonly TypeNode[] | undefined): TypeNode { const { imports, paths } = this.#dependencies; + const fullyQualifiedName = convertReferenceSchemaToFullyQualifiedName(schema); + + if (this.#transferTypes.has(fullyQualifiedName)) { + return this.#transferTypes.get(fullyQualifiedName)!(typeArguments); + } + const specifier = convertReferenceSchemaToSpecifier(schema); - const path = paths.createRelativePath(convertReferenceSchemaToPath(schema)); + const path = paths.createRelativePath(convertFullyQualifiedNameToRelativePath(fullyQualifiedName)); const identifier = imports.default.getIdentifier(path) ?? imports.default.add(path, specifier, true); diff --git a/packages/ts/generator-plugin-backbone/src/index.ts b/packages/ts/generator-plugin-backbone/src/index.ts index 5cfaf6d4eb..ea2f7d1f59 100644 --- a/packages/ts/generator-plugin-backbone/src/index.ts +++ b/packages/ts/generator-plugin-backbone/src/index.ts @@ -1,5 +1,5 @@ import Plugin from '@vaadin/hilla-generator-core/Plugin.js'; -import type SharedStorage from '@vaadin/hilla-generator-core/SharedStorage.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'; @@ -53,8 +53,8 @@ export default class BackbonePlugin extends Plugin { }); const processors = await Promise.all( - [...endpoints.entries()].map(async ([endpointName, methods]) => - EndpointProcessor.create(endpointName, this, methods, storage.outputDir), + Array.from(endpoints.entries(), async ([endpointName, methods]) => + EndpointProcessor.create(endpointName, methods, storage, this), ), ); @@ -66,7 +66,7 @@ export default class BackbonePlugin extends Plugin { return storage.api.components?.schemas ? Object.entries(storage.api.components.schemas).map(([name, component]) => - new EntityProcessor(name, component, this).process(), + new EntityProcessor(name, component, storage, this).process(), ) : []; } diff --git a/packages/ts/generator-plugin-barrel/src/BarrelProcessor.ts b/packages/ts/generator-plugin-barrel/src/BarrelProcessor.ts index 42f0b0c091..b74ff86697 100644 --- a/packages/ts/generator-plugin-barrel/src/BarrelProcessor.ts +++ b/packages/ts/generator-plugin-barrel/src/BarrelProcessor.ts @@ -6,7 +6,7 @@ import PathManager from '@vaadin/hilla-generator-utils/dependencies/PathManager. import type { SourceFile } from 'typescript'; export default class BarrelProcessor { - static readonly BARREL_FILE_NAME = 'endpoints.ts'; + static readonly BARREL_FILE_NAME = 'endpoints'; declare ['constructor']: typeof BarrelProcessor; readonly #endpoints: readonly SourceFile[]; readonly #outputPathManager = new PathManager({ extension: 'ts' }); @@ -18,7 +18,7 @@ export default class BarrelProcessor { } process(): SourceFile { - this.#owner.logger.debug(`Generating '${this.constructor.BARREL_FILE_NAME}' file`); + this.#owner.logger.debug(`Generating '${this.constructor.BARREL_FILE_NAME}.ts' file`); const { exports, imports } = this.#endpoints.reduce( (acc, { fileName }) => { @@ -35,7 +35,7 @@ export default class BarrelProcessor { return createSourceFile( [...imports.toCode(), ...exports.toCode()], - this.#outputPathManager.createRelativePath('endpoints'), + this.#outputPathManager.createRelativePath(this.constructor.BARREL_FILE_NAME), ); } } diff --git a/packages/ts/generator-plugin-barrel/src/index.ts b/packages/ts/generator-plugin-barrel/src/index.ts index 1d28b4649e..86239fd371 100644 --- a/packages/ts/generator-plugin-barrel/src/index.ts +++ b/packages/ts/generator-plugin-barrel/src/index.ts @@ -1,5 +1,5 @@ import Plugin from '@vaadin/hilla-generator-core/Plugin.js'; -import type SharedStorage from '@vaadin/hilla-generator-core/SharedStorage.js'; +import type { SharedStorage } from '@vaadin/hilla-generator-core/SharedStorage.js'; import BackbonePlugin, { BackbonePluginSourceType } from '@vaadin/hilla-generator-plugin-backbone'; import PluginError from '@vaadin/hilla-generator-utils/PluginError.js'; import type { SourceFile } from 'typescript'; diff --git a/packages/ts/generator-plugin-client/src/index.ts b/packages/ts/generator-plugin-client/src/index.ts index 44d195aa6d..e8d01914bf 100644 --- a/packages/ts/generator-plugin-client/src/index.ts +++ b/packages/ts/generator-plugin-client/src/index.ts @@ -1,7 +1,7 @@ import { open } from 'fs/promises'; import { fileURLToPath } from 'url'; import Plugin from '@vaadin/hilla-generator-core/Plugin.js'; -import type SharedStorage from '@vaadin/hilla-generator-core/SharedStorage.js'; +import type { SharedStorage } from '@vaadin/hilla-generator-core/SharedStorage.js'; import ClientProcessor from './ClientProcessor.js'; export default class ClientPlugin extends Plugin { diff --git a/packages/ts/generator-plugin-model/src/EntityModelProcessor.ts b/packages/ts/generator-plugin-model/src/EntityModelProcessor.ts index a23c5639fe..9b4b0a4919 100644 --- a/packages/ts/generator-plugin-model/src/EntityModelProcessor.ts +++ b/packages/ts/generator-plugin-model/src/EntityModelProcessor.ts @@ -1,6 +1,7 @@ /* eslint-disable symbol-description */ import { dirname } from 'path/posix'; import { + convertFullyQualifiedNameToRelativePath, convertReferenceSchemaToPath, convertReferenceSchemaToSpecifier, decomposeSchema, @@ -11,11 +12,8 @@ import { type ObjectSchema, type ReferenceSchema, type Schema, -} from '@vaadin/hilla-generator-core/Schema.js'; -import { - convertFullyQualifiedNameToRelativePath, simplifyFullyQualifiedName, -} from '@vaadin/hilla-generator-core/utils.js'; +} from '@vaadin/hilla-generator-core/Schema.js'; 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'; @@ -27,7 +25,7 @@ import ts, { type Statement, } from 'typescript'; import { ModelSchemaExpressionProcessor, ModelSchemaTypeProcessor } from './ModelSchemaProcessor.js'; -import { importBuiltInFormModel, type Context, createModelBuildingCallback, createEmptyValueMaker } from './utils.js'; +import { type Context, createEmptyValueMaker, createModelBuildingCallback, importBuiltInFormModel } from './utils.js'; export type DependencyData = Readonly<{ id: Identifier; diff --git a/packages/ts/generator-plugin-model/src/index.ts b/packages/ts/generator-plugin-model/src/index.ts index 67f8146e76..92638bf21b 100644 --- a/packages/ts/generator-plugin-model/src/index.ts +++ b/packages/ts/generator-plugin-model/src/index.ts @@ -1,5 +1,5 @@ import Plugin from '@vaadin/hilla-generator-core/Plugin.js'; -import type SharedStorage from '@vaadin/hilla-generator-core/SharedStorage.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'; diff --git a/packages/ts/generator-plugin-push/src/index.ts b/packages/ts/generator-plugin-push/src/index.ts index a6a5dd31d0..3135775cf0 100644 --- a/packages/ts/generator-plugin-push/src/index.ts +++ b/packages/ts/generator-plugin-push/src/index.ts @@ -1,5 +1,5 @@ import Plugin from '@vaadin/hilla-generator-core/Plugin.js'; -import type SharedStorage from '@vaadin/hilla-generator-core/SharedStorage.js'; +import type { SharedStorage } from '@vaadin/hilla-generator-core/SharedStorage.js'; import type { OpenAPIV3 } from 'openapi-types'; import type { ReadonlyObjectDeep } from 'type-fest/source/readonly-deep'; import { type EndpointOperations, PushProcessor } from './PushProcessor.js'; diff --git a/packages/ts/generator-plugin-signals/src/index.ts b/packages/ts/generator-plugin-signals/src/index.ts index 2242af4791..487ba37430 100644 --- a/packages/ts/generator-plugin-signals/src/index.ts +++ b/packages/ts/generator-plugin-signals/src/index.ts @@ -1,5 +1,5 @@ import Plugin from '@vaadin/hilla-generator-core/Plugin.js'; -import type SharedStorage from '@vaadin/hilla-generator-core/SharedStorage.js'; +import type { SharedStorage } from '@vaadin/hilla-generator-core/SharedStorage.js'; import type { OpenAPIV3 } from 'openapi-types'; import SignalProcessor from './SignalProcessor.js'; diff --git a/packages/ts/generator-plugin-subtypes/src/ModelFixProcessor.ts b/packages/ts/generator-plugin-subtypes/src/ModelFixProcessor.ts index ae2b954a97..6ec356dfe0 100644 --- a/packages/ts/generator-plugin-subtypes/src/ModelFixProcessor.ts +++ b/packages/ts/generator-plugin-subtypes/src/ModelFixProcessor.ts @@ -1,12 +1,6 @@ import createSourceFile from '@vaadin/hilla-generator-utils/createSourceFile.js'; -import ts, { type PropertyName, type SourceFile } from 'typescript'; - -function propertyNameToString(node: PropertyName): string | null { - if (ts.isIdentifier(node) || ts.isStringLiteral(node) || ts.isNumericLiteral(node)) { - return node.text; - } - return null; -} +import ts, { type SourceFile } from 'typescript'; +import { propertyNameToString } from './utils.js'; export class ModelFixProcessor { readonly #source: SourceFile; diff --git a/packages/ts/generator-plugin-subtypes/src/SubTypesProcessor.ts b/packages/ts/generator-plugin-subtypes/src/SubTypesProcessor.ts index 04c1a42d47..acae8c2b39 100644 --- a/packages/ts/generator-plugin-subtypes/src/SubTypesProcessor.ts +++ b/packages/ts/generator-plugin-subtypes/src/SubTypesProcessor.ts @@ -3,20 +3,20 @@ import { convertReferenceSchemaToPath, convertReferenceSchemaToSpecifier, type ReferenceSchema, + simplifyFullyQualifiedName, } from '@vaadin/hilla-generator-core/Schema.js'; -import { simplifyFullyQualifiedName } from '@vaadin/hilla-generator-core/utils.js'; 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 ts from 'typescript'; +import ts, { type SourceFile } from 'typescript'; export class SubTypesProcessor { readonly #typeName: string; - readonly #source: ts.SourceFile; + readonly #source: SourceFile; readonly #oneOf: ReferenceSchema[]; readonly #dependencies; - constructor(typeName: string, source: ts.SourceFile, oneOf: ReferenceSchema[]) { + constructor(typeName: string, source: SourceFile, oneOf: ReferenceSchema[]) { this.#typeName = typeName; this.#source = source; this.#oneOf = oneOf; @@ -25,17 +25,17 @@ export class SubTypesProcessor { ); } - process(): ts.SourceFile { + process(): SourceFile { const { exports, imports, paths } = this.#dependencies; - // import all sub types and return them + // import all subtypes and return them const subTypes = this.#oneOf.map((schema) => { const path = paths.createRelativePath(convertReferenceSchemaToPath(schema)); const subType = convertReferenceSchemaToSpecifier(schema); return imports.default.add(path, subType, true); }); - // create a union type from the sub types + // create a union type from the subtypes const union = ts.factory.createUnionTypeNode( subTypes.map((subType) => ts.factory.createTypeReferenceNode(subType)), ); diff --git a/packages/ts/generator-plugin-subtypes/src/TypeFixProcessor.ts b/packages/ts/generator-plugin-subtypes/src/TypeFixProcessor.ts index d47335cf41..279ed98553 100644 --- a/packages/ts/generator-plugin-subtypes/src/TypeFixProcessor.ts +++ b/packages/ts/generator-plugin-subtypes/src/TypeFixProcessor.ts @@ -1,15 +1,9 @@ import createSourceFile from '@vaadin/hilla-generator-utils/createSourceFile.js'; -import ts from 'typescript'; - -function propertyNameToString(node: ts.PropertyName): string | null { - if (ts.isIdentifier(node) || ts.isStringLiteral(node) || ts.isNumericLiteral(node)) { - return node.text; - } - return null; -} +import ts, { type SourceFile } from 'typescript'; +import { propertyNameToString } from './utils.js'; export class TypeFixProcessor { - readonly #source: ts.SourceFile; + readonly #source: SourceFile; readonly #typeValue: string; constructor(source: ts.SourceFile, typeValue: string) { @@ -17,7 +11,7 @@ export class TypeFixProcessor { this.#typeValue = typeValue; } - process(): ts.SourceFile { + process(): SourceFile { const statements = this.#source.statements.map((statement) => { // search in the interface definition if (ts.isInterfaceDeclaration(statement)) { diff --git a/packages/ts/generator-plugin-subtypes/src/index.ts b/packages/ts/generator-plugin-subtypes/src/index.ts index 5aaf296f69..2db37889ad 100644 --- a/packages/ts/generator-plugin-subtypes/src/index.ts +++ b/packages/ts/generator-plugin-subtypes/src/index.ts @@ -1,7 +1,7 @@ import Plugin from '@vaadin/hilla-generator-core/Plugin.js'; -import type { ReferenceSchema } from '@vaadin/hilla-generator-core/Schema.js'; -import type SharedStorage from '@vaadin/hilla-generator-core/SharedStorage.js'; -import { convertFullyQualifiedNameToRelativePath } from '@vaadin/hilla-generator-core/utils.js'; +import { 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'; @@ -29,13 +29,17 @@ export default class SubTypesPlugin extends Plugin { 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).process(); + const newSource = new SubTypesProcessor( + baseKey, + source, + baseComponent.oneOf as OpenAPIV3.ReferenceObject[], + ).process(); sources.splice(sources.indexOf(source), 1, newSource); // mentioned types in the oneOf need to be fixed as well - baseComponent.oneOf.forEach((schema) => { + (baseComponent.oneOf as OpenAPIV3.ReferenceObject[]).forEach((schema) => { if ('$ref' in schema) { - const path = (schema as ReferenceSchema).$ref; + const path = schema.$ref; Object.entries(components).forEach(([subKey, subComponent]) => { if ('anyOf' in subComponent && subKey === path.substring('#/components/schemas/'.length)) { subComponent.anyOf?.forEach((s) => { diff --git a/packages/ts/generator-plugin-subtypes/src/utils.ts b/packages/ts/generator-plugin-subtypes/src/utils.ts new file mode 100644 index 0000000000..853439973f --- /dev/null +++ b/packages/ts/generator-plugin-subtypes/src/utils.ts @@ -0,0 +1,8 @@ +import ts, { type PropertyName } from 'typescript'; + +export function propertyNameToString(node: PropertyName): string | null { + if (ts.isIdentifier(node) || ts.isStringLiteral(node) || ts.isNumericLiteral(node)) { + return node.text; + } + return null; +} diff --git a/packages/ts/generator-plugin-transfertypes/.eslintrc b/packages/ts/generator-plugin-transfertypes/.eslintrc new file mode 100644 index 0000000000..6ac92d4ca9 --- /dev/null +++ b/packages/ts/generator-plugin-transfertypes/.eslintrc @@ -0,0 +1,6 @@ +{ + "extends": ["../../../.eslintrc"], + "parserOptions": { + "project": "./tsconfig.json" + } +} diff --git a/packages/ts/generator-plugin-transfertypes/.lintstagedrc.js b/packages/ts/generator-plugin-transfertypes/.lintstagedrc.js new file mode 100644 index 0000000000..937dc6639f --- /dev/null +++ b/packages/ts/generator-plugin-transfertypes/.lintstagedrc.js @@ -0,0 +1,6 @@ +import { commands, extensions } from '../../../.lintstagedrc.js'; + +export default { + [`src/**/*.{${extensions}}`]: commands, + [`test/**/*.{${extensions}}`]: commands, +}; diff --git a/packages/ts/generator-plugin-transfertypes/LICENSE b/packages/ts/generator-plugin-transfertypes/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/packages/ts/generator-plugin-transfertypes/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/packages/ts/generator-plugin-transfertypes/README.md b/packages/ts/generator-plugin-transfertypes/README.md new file mode 100644 index 0000000000..a9856d9bc1 --- /dev/null +++ b/packages/ts/generator-plugin-transfertypes/README.md @@ -0,0 +1 @@ +# Hilla TypeScript Generator JsonSubTypes Support Plugin diff --git a/packages/ts/generator-plugin-transfertypes/package.json b/packages/ts/generator-plugin-transfertypes/package.json new file mode 100644 index 0000000000..ba0326e9de --- /dev/null +++ b/packages/ts/generator-plugin-transfertypes/package.json @@ -0,0 +1,61 @@ +{ + "name": "@vaadin/hilla-generator-plugin-transfertypes", + "version": "24.7.0-alpha10", + "description": "A plugin to replace types in the generated code", + "main": "index.js", + "type": "module", + "engines": { + "node": ">= 16.13" + }, + "scripts": { + "clean:build": "git clean -fx . -e .vite -e node_modules", + "build": "concurrently npm:build:*", + "build:transpile": "tsc --isolatedModules -p tsconfig.build.json", + "build:copy": "cd src && copyfiles **/*.d.ts ..", + "lint": "eslint src test", + "lint:fix": "eslint src test --fix", + "test": "vitest --run", + "test:update": "vitest --update", + "test:coverage": "vitest --coverage", + "typecheck": "tsc --noEmit" + }, + "exports": { + ".": { + "default": "./index.js" + }, + "./index.js": { + "default": "./index.js" + } + }, + "repository": { + "type": "git", + "url": "https://github.com/vaadin/hilla.git", + "directory": "packages/ts/generator-plugin-transfertypes" + }, + "keywords": [ + "hilla", + "typescript", + "generator" + ], + "author": "Vaadin Ltd.", + "license": "Apache 2.0", + "bugs": { + "url": "https://github.com/vaadin/hilla/issues" + }, + "homepage": "https://hilla.dev", + "files": [ + "*.{d.ts.map,d.ts,js.map,js}" + ], + "publishConfig": { + "access": "public" + }, + "dependencies": { + "@vaadin/hilla-generator-core": "24.7.0-alpha10", + "@vaadin/hilla-generator-plugin-client": "24.7.0-alpha10", + "@vaadin/hilla-generator-plugin-model": "24.7.0-alpha10", + "@vaadin/hilla-generator-utils": "24.7.0-alpha10", + "fast-deep-equal": "3.1.3", + "openapi-types": "12.1.3", + "typescript": "5.7.3" + } +} diff --git a/packages/ts/generator-plugin-transfertypes/src/index.ts b/packages/ts/generator-plugin-transfertypes/src/index.ts new file mode 100644 index 0000000000..26b4bd0c00 --- /dev/null +++ b/packages/ts/generator-plugin-transfertypes/src/index.ts @@ -0,0 +1,20 @@ +import Plugin from '@vaadin/hilla-generator-core/Plugin.js'; +import type { SharedStorage } from '@vaadin/hilla-generator-core/SharedStorage.js'; +import type { Writable } from 'type-fest'; +import ts from 'typescript'; + +export default class TransferTypesPlugin extends Plugin { + override get path(): string { + return import.meta.url; + } + + override execute({ api: { components }, transferTypes }: SharedStorage): void { + transferTypes.set('com.vaadin.hilla.runtime.transfertypes.File', () => ts.factory.createTypeReferenceNode('File')); + + if (components?.schemas) { + (components as Writable).schemas = Object.fromEntries( + Object.entries(components.schemas).filter(([key]) => key !== 'com.vaadin.hilla.runtime.transfertypes.File'), + ); + } + } +} diff --git a/packages/ts/generator-plugin-transfertypes/test/file-type/MultipartFile.json b/packages/ts/generator-plugin-transfertypes/test/file-type/MultipartFile.json new file mode 100644 index 0000000000..8fb7e41a4f --- /dev/null +++ b/packages/ts/generator-plugin-transfertypes/test/file-type/MultipartFile.json @@ -0,0 +1,60 @@ +{ + "openapi" : "3.0.1", + "info" : { + "title" : "Hilla Application", + "version" : "1.0.0" + }, + "servers" : [ + { + "url" : "http://localhost:8080/connect", + "description" : "Hilla Backend" + } + ], + "tags" : [ + { + "name" : "MultipartFileEndpoint", + "x-class-name" : "com.vaadin.hilla.parser.plugins.transfertypes.file.MultipartFileEndpoint" + } + ], + "paths" : { + "/MultipartFileEndpoint/uploadFile" : { + "post" : { + "tags" : [ + "MultipartFileEndpoint" + ], + "operationId" : "MultipartFileEndpoint_uploadFile_POST", + "requestBody" : { + "content" : { + "application/json" : { + "schema" : { + "type" : "object", + "properties" : { + "file" : { + "nullable" : true, + "anyOf" : [ + { + "$ref" : "#/components/schemas/com.vaadin.hilla.runtime.transfertypes.File" + } + ] + } + } + } + } + } + }, + "responses" : { + "200" : { + "description" : "" + } + } + } + } + }, + "components" : { + "schemas" : { + "com.vaadin.hilla.runtime.transfertypes.File" : { + "type" : "object" + } + } + } +} diff --git a/packages/ts/generator-plugin-transfertypes/test/file-type/MultipartFile.spec.ts b/packages/ts/generator-plugin-transfertypes/test/file-type/MultipartFile.spec.ts new file mode 100644 index 0000000000..786f60c592 --- /dev/null +++ b/packages/ts/generator-plugin-transfertypes/test/file-type/MultipartFile.spec.ts @@ -0,0 +1,18 @@ +import BackbonePlugin from '@vaadin/hilla-generator-plugin-backbone'; +import { describe, it, expect } from 'vitest'; +import TransferTypesPlugin from '../../src/index.js'; +import { createGenerator, loadInput } from '../utils/common.js'; + +describe('TransferTypesPlugin', () => { + describe('for MultipartFile type', () => { + it('correctly replaces the incoming type', async () => { + const sectionName = 'MultipartFile'; + const generator = createGenerator([TransferTypesPlugin, BackbonePlugin]); + const input = await loadInput(sectionName, import.meta.url); + const files = await generator.process(input); + expect(files).to.have.length(1); + expect(files[0].name).to.equal('MultipartFileEndpoint.ts'); + await expect(await files[0].text()).toMatchFileSnapshot('./fixtures/MultipartFileEndpoint.snap.ts'); + }); + }); +}); diff --git a/packages/ts/generator-plugin-transfertypes/test/file-type/fixtures/MultipartFileEndpoint.snap.ts b/packages/ts/generator-plugin-transfertypes/test/file-type/fixtures/MultipartFileEndpoint.snap.ts new file mode 100644 index 0000000000..91477191d6 --- /dev/null +++ b/packages/ts/generator-plugin-transfertypes/test/file-type/fixtures/MultipartFileEndpoint.snap.ts @@ -0,0 +1,4 @@ +import { EndpointRequestInit as EndpointRequestInit_1 } from "@vaadin/hilla-frontend"; +import client_1 from "./connect-client.default.js"; +async function uploadFile_1(file: File | undefined, init?: EndpointRequestInit_1): Promise { return client_1.call("MultipartFileEndpoint", "uploadFile", { file }, init); } +export { uploadFile_1 as uploadFile }; diff --git a/packages/ts/generator-plugin-transfertypes/test/utils/common.ts b/packages/ts/generator-plugin-transfertypes/test/utils/common.ts new file mode 100644 index 0000000000..85af6fa91f --- /dev/null +++ b/packages/ts/generator-plugin-transfertypes/test/utils/common.ts @@ -0,0 +1,14 @@ +import { readFile } from 'node:fs/promises'; +import Generator from '@vaadin/hilla-generator-core/Generator.js'; +import type { PluginConstructor } from '@vaadin/hilla-generator-core/Plugin.js'; +import LoggerFactory from '@vaadin/hilla-generator-utils/LoggerFactory.js'; + +export const pathBase = 'com/vaadin/hilla/parser/plugins/transfertypes'; + +export function createGenerator(plugins: readonly PluginConstructor[]): Generator { + return new Generator(plugins, { logger: new LoggerFactory({ name: 'tsgen-test-transfertypes', verbose: true }) }); +} + +export async function loadInput(name: string, importMeta: string): Promise { + return readFile(new URL(`./${name}.json`, importMeta), 'utf8'); +} diff --git a/packages/ts/generator-plugin-transfertypes/tsconfig.build.json b/packages/ts/generator-plugin-transfertypes/tsconfig.build.json new file mode 100644 index 0000000000..445f3f4492 --- /dev/null +++ b/packages/ts/generator-plugin-transfertypes/tsconfig.build.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "rootDir": "src", + "outDir": "." + }, + "include": ["src"] +} diff --git a/packages/ts/generator-plugin-transfertypes/tsconfig.json b/packages/ts/generator-plugin-transfertypes/tsconfig.json new file mode 100644 index 0000000000..cf0eb8454e --- /dev/null +++ b/packages/ts/generator-plugin-transfertypes/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../../tsconfig.json", + "include": ["src", "test"], + "exclude": ["test/**/*.snap.ts"] +} diff --git a/packages/ts/generator-plugin-transfertypes/vitest.config.ts b/packages/ts/generator-plugin-transfertypes/vitest.config.ts new file mode 100644 index 0000000000..cfb31652df --- /dev/null +++ b/packages/ts/generator-plugin-transfertypes/vitest.config.ts @@ -0,0 +1,3 @@ +import sharedConfig from '../../../scripts/vite/node.vitest.config.js'; + +export default sharedConfig; diff --git a/scripts/build.ts b/scripts/build.ts index 1a6c10a128..d5ddcbb9fb 100644 --- a/scripts/build.ts +++ b/scripts/build.ts @@ -11,7 +11,7 @@ const scriptsDir = new URL('./', import.meta.url); const packageRoot = pathToFileURL(process.cwd() + sep); const [packageJsonFile, srcFiles] = await Promise.all([ readFile(new URL('package.json', packageRoot), 'utf8'), - glob('src/**/*.{ts,tsx,obj.css}', { ignore: ['**/*.d.ts'] }), + glob('src/**/*.{ts,tsx,obj.css}', { ignore: ['**/*.d.ts', '**/*.t.ts'] }), ]); const packageJson: PackageJson = JSON.parse(packageJsonFile); @@ -55,7 +55,7 @@ await build({ // Adds a __REGISTER__ function definition everywhere in the built code where // the call for that function exists. inject: [fileURLToPath(new URL('./register.js', scriptsDir))], - entryPoints: srcFiles.map((file) => new URL(file, packageRoot)).map(fileURLToPath), + entryPoints: srcFiles.map((file) => new URL(file, packageRoot)).map((url) => fileURLToPath(url)), format: 'esm', outdir: fileURLToPath(packageRoot), packages: 'external',