From 27020423fa56683cc3baa760b5cc91b539500963 Mon Sep 17 00:00:00 2001 From: Olivier Costi Date: Tue, 10 Mar 2026 10:54:16 +0100 Subject: [PATCH 1/6] feat: improve support for included entity references --- src/generator/04-services/endpoints/some.ts | 108 ++++++++++++++++++-- 1 file changed, 99 insertions(+), 9 deletions(-) diff --git a/src/generator/04-services/endpoints/some.ts b/src/generator/04-services/endpoints/some.ts index 6983699..2893122 100644 --- a/src/generator/04-services/endpoints/some.ts +++ b/src/generator/04-services/endpoints/some.ts @@ -1,17 +1,18 @@ -import { resolveResponseType } from '../../../target'; import { GeneratedServiceFunction, ServiceFunctionGenerator } from '@generator/04-services/types'; import { generateArrowFunction } from '@ts/generateArrowFunction'; import { generateArrowFunctionType } from '@ts/generateArrowFunctionType'; import { generateInterfaceFromObject, generateInterfaceType, InterfaceProperty } from '@ts/generateInterface'; +import { generateObject, ObjectProperty } from '@ts/generateObject'; import { generateString } from '@ts/generateString'; +import { generateType } from '@ts/generateType'; import { convertToTypeScriptType, createObjectType } from '@utils/openapi/convertToTypeScriptType'; import { isObjectSchemaObject, isParameterObject, isResponseObject } from '@utils/openapi/guards'; import { pascalCase } from 'change-case'; import { OpenAPIV3 } from 'openapi-types'; -import { generateType } from '@ts/generateType'; +import { resolveResponseType } from '../../../target'; import { GeneratedEntity } from '../../03-entities'; -import { resolveResponsesObject } from '../utils/resolveResponsesObject'; import { resolveParameters } from '../utils/resolveParameters'; +import { resolveResponsesObject } from '../utils/resolveResponsesObject'; const excludedParameters = [ 'page', @@ -41,23 +42,108 @@ const resolveAdditionalPropertiesSchema = ({ responses }: OpenAPIV3.OperationObj return undefined; }; +const resolveArrayReferenceProperties = ( + entity: string, + entities: Map, + visitedEntities = new Set() +): ObjectProperty[] => { + if (!entity || visitedEntities.has(entity)) { + return []; + } + + const generatedEntity = entities.get(entity); + if (!generatedEntity) { + return []; + } + + const nextVisitedEntities = new Set(visitedEntities); + nextVisitedEntities.add(entity); + + const properties: ObjectProperty[] = [...generatedEntity.properties.entries()].flatMap( + ([property, propertyMetaData]): ObjectProperty[] => { + if (propertyMetaData.type === 'array') { + if (propertyMetaData.entity === 'onlyId') { + return [{ key: property, value: [{ key: 'id', value: 'string' }] }]; + } + + if (!propertyMetaData.entity) { + return []; + } + + const nestedProperties = resolveArrayReferenceProperties( + propertyMetaData.entity, + entities, + nextVisitedEntities + ); + + if (!nestedProperties.length) { + return []; + } + + return [{ key: property, value: nestedProperties }]; + } + + if (property.endsWith('Id')) { + return [{ key: property, value: 'string' }]; + } + + return []; + } + ); + + if (generatedEntity.parentName) { + properties.push(...resolveArrayReferenceProperties(generatedEntity.parentName, entities, nextVisitedEntities)); + } + + return properties; +}; + +// TODO: remove boolean from arrays in QuerySelect const resolveReferences = (entity: string, entities: Map) => { const references: InterfaceProperty[] = []; const generatedEntity = entities.get(entity); if (generatedEntity) { + if (entity === 'warehouseStock') { + console.log('generatedEntity', generatedEntity); + } for (const [property, propertyMetaData] of generatedEntity.properties) { - if (propertyMetaData.service) { - references.push({ - name: property, - type: generateString(propertyMetaData.service), - required: true - }); + // TODO: filter things like tags in opportunity + if (propertyMetaData.type === 'array') { + if (propertyMetaData.entity === 'onlyId') { + references.push({ + name: property, + type: generateObject([{ key: 'id', value: 'string' }]), + required: true + }); + } else { + const nestedProperties = resolveArrayReferenceProperties(propertyMetaData.entity || '', entities); + if (nestedProperties.length) { + references.push({ + name: property, + type: generateObject(nestedProperties), + required: true + }); + } + } + } else { + if (propertyMetaData.service) { + references.push({ + name: property, + // TODO: maybe just string + type: generateString(propertyMetaData.service), + required: true + }); + } } } if (generatedEntity.parentName) { references.push(...resolveReferences(generatedEntity.parentName, entities)); } } + + if (entity === 'warehouseStock') { + console.log('references', references); + } return references; }; @@ -115,6 +201,10 @@ export const generateSomeEndpoint: ServiceFunctionGenerator = ({ const referencesTypeName = `${functionTypeName}_References`; const referencesTypeSource = generateInterfaceType(referencesTypeName, resolveReferences(endpoint.service, entities)); + // if (endpoint.service === 'warehouseStock') { + // console.log('referencesTypeSource', referencesTypeSource); + // } + const additionalPropertyTypeName = `${functionTypeName}_AdditionalProperty`; const additionalPropertyTypeSource = generateType(additionalPropertyTypeName, 'string'); From 0a0ab2da4183460015f7bf3fc8bf70a46e529ade Mon Sep 17 00:00:00 2001 From: Olivier Costi Date: Tue, 10 Mar 2026 12:03:45 +0100 Subject: [PATCH 2/6] feat: add global type for referenced entities global --- src/generator/01-base/static/types.ts.txt | 4 +- src/generator/03-entities/index.ts | 24 +++++++++-- src/generator/04-services/endpoints/some.ts | 46 ++------------------- src/generator/generate.ts | 9 ++-- 4 files changed, 32 insertions(+), 51 deletions(-) diff --git a/src/generator/01-base/static/types.ts.txt b/src/generator/01-base/static/types.ts.txt index 56986e4..2e5e7e8 100644 --- a/src/generator/01-base/static/types.ts.txt +++ b/src/generator/01-base/static/types.ts.txt @@ -62,9 +62,9 @@ export type UniqueQuery = { serializeNulls?: boolean; }; -export type SomeQueryReturn = { +export type SomeQueryReturn = { entities: E[]; - references?: R; + references?: ReferencedEntities; properties?: P[]; }; diff --git a/src/generator/03-entities/index.ts b/src/generator/03-entities/index.ts index a85d70e..cf0cfec 100644 --- a/src/generator/03-entities/index.ts +++ b/src/generator/03-entities/index.ts @@ -1,12 +1,12 @@ import { extractPropertyMetaData, PropertyMetaData } from '@generator/03-entities/utils/extractPropertyMetaData'; -import { generateInterface, InterfaceProperty } from '@ts/generateInterface'; +import { logger } from '@logger'; +import { generateInterface, generateInterfaceType, InterfaceProperty } from '@ts/generateInterface'; import { generateStatements } from '@ts/generateStatements'; import { loosePascalCase } from '@utils/case'; import { convertToTypeScriptType, createReferenceType, getRefName } from '@utils/openapi/convertToTypeScriptType'; import { ExtendedSchema, isEnumSchemaObject, isReferenceObject } from '@utils/openapi/guards'; -import { OpenAPIV3 } from 'openapi-types'; -import { logger } from '@logger'; import { OpenApiContext } from '@utils/weclapp/extractContext'; +import { OpenAPIV3 } from 'openapi-types'; export interface GeneratedEntity { name: string; @@ -23,6 +23,13 @@ export interface GeneratedEntity { export const FILTER_PROPS_SUFFIX = 'Filter_Props'; +const excludedReferencedEntities = new Set([ + 'abstractParty', + 'abstractEntity', + 'abstractEntityWithCustomAttributes', + 'onlyId' +]); + export const generateEntities = (context: OpenApiContext): Map => { const entities: Map = new Map(); @@ -144,3 +151,14 @@ export const generateEntities = (context: OpenApiContext): Map) => { + const referencedEntities = [...entities.values()] + .filter((entity) => !excludedReferencedEntities.has(entity.name)) + .map((entity) => ({ + name: entity.name, + type: `${entity.interfaceName}[]` + })); + + return generateInterfaceType('ReferencedEntities', referencedEntities); +}; diff --git a/src/generator/04-services/endpoints/some.ts b/src/generator/04-services/endpoints/some.ts index 2893122..c3a1d30 100644 --- a/src/generator/04-services/endpoints/some.ts +++ b/src/generator/04-services/endpoints/some.ts @@ -98,16 +98,13 @@ const resolveArrayReferenceProperties = ( return properties; }; +// TODO: check v1 and v2 // TODO: remove boolean from arrays in QuerySelect const resolveReferences = (entity: string, entities: Map) => { const references: InterfaceProperty[] = []; const generatedEntity = entities.get(entity); if (generatedEntity) { - if (entity === 'warehouseStock') { - console.log('generatedEntity', generatedEntity); - } for (const [property, propertyMetaData] of generatedEntity.properties) { - // TODO: filter things like tags in opportunity if (propertyMetaData.type === 'array') { if (propertyMetaData.entity === 'onlyId') { references.push({ @@ -129,8 +126,7 @@ const resolveReferences = (entity: string, entities: Map) => { - const referencedEntities: InterfaceProperty[] = []; - const generatedEntity = entities.get(entity); - if (generatedEntity) { - for (const [, propertyMetaData] of generatedEntity.properties) { - if (propertyMetaData.service && propertyMetaData.entity) { - const referencedEntity = entities.get(propertyMetaData.entity); - if (referencedEntity) - referencedEntities.push({ - name: propertyMetaData.service, - type: `${referencedEntity.interfaceName}[]`, - required: true - }); - } - } - if (generatedEntity.parentName) { - referencedEntities.push(...resolveReferencedEntities(generatedEntity.parentName, entities)); - } - } - return referencedEntities; -}; - export const generateSomeEndpoint: ServiceFunctionGenerator = ({ endpoint, operationObject, @@ -201,10 +172,6 @@ export const generateSomeEndpoint: ServiceFunctionGenerator = ({ const referencesTypeName = `${functionTypeName}_References`; const referencesTypeSource = generateInterfaceType(referencesTypeName, resolveReferences(endpoint.service, entities)); - // if (endpoint.service === 'warehouseStock') { - // console.log('referencesTypeSource', referencesTypeSource); - // } - const additionalPropertyTypeName = `${functionTypeName}_AdditionalProperty`; const additionalPropertyTypeSource = generateType(additionalPropertyTypeName, 'string'); @@ -214,12 +181,6 @@ export const generateSomeEndpoint: ServiceFunctionGenerator = ({ `SomeQuery<${relatedEntity.interfaceName}, ${filterTypeName}, ${referencesTypeName}, ${additionalPropertyTypeName}> & ${parametersTypeName}` ); - const referencedEntitiesTypeName = `${functionTypeName}_ReferencedEntities`; - const referencedEntitiesTypeSource = generateInterfaceType( - referencedEntitiesTypeName, - resolveReferencedEntities(endpoint.service, entities) - ); - const additionalPropertiesTypeName = `${functionTypeName}_AdditionalProperties`; const additionalPropertiesSchema = resolveAdditionalPropertiesSchema(operationObject); const additionalPropertiesTypeSource = generateType( @@ -230,7 +191,7 @@ export const generateSomeEndpoint: ServiceFunctionGenerator = ({ const functionTypeSource = generateArrowFunctionType({ type: functionTypeName, params: [`query${parametersType.isFullyOptional() ? '?' : ''}: ${queryTypeName}, requestOptions?: RequestOptions`], - returns: `${resolveResponseType(options.target)}>` + returns: `${resolveResponseType(options.target)}>` }); const functionSource = generateArrowFunction({ @@ -250,7 +211,6 @@ export const generateSomeEndpoint: ServiceFunctionGenerator = ({ { name: referencesTypeName, source: referencesTypeSource }, { name: additionalPropertyTypeName, source: additionalPropertyTypeSource }, { name: queryTypeName, source: queryTypeSource }, - { name: referencedEntitiesTypeName, source: referencedEntitiesTypeSource }, { name: additionalPropertiesTypeName, source: additionalPropertiesTypeSource } ] }; diff --git a/src/generator/generate.ts b/src/generator/generate.ts index 36d5a76..3a16a9f 100644 --- a/src/generator/generate.ts +++ b/src/generator/generate.ts @@ -1,13 +1,13 @@ -import { Target } from '../target'; import { generateBase } from '@generator/01-base'; import { generateEnums } from '@generator/02-enums'; -import { generateEntities } from '@generator/03-entities'; +import { generateEntities, generateReferencedEntities } from '@generator/03-entities'; import { generateServices } from '@generator/04-services'; import { generateMaps } from '@generator/05-maps'; import { generateBlockComment } from '@ts/generateComment'; import { generateStatements } from '@ts/generateStatements'; import { extractContext } from '@utils/weclapp/extractContext'; import { OpenAPIV3 } from 'openapi-types'; +import { Target } from '../target'; export interface GeneratorOptions { /* Generate unique methods as well. */ @@ -34,7 +34,10 @@ export const generate = (doc: OpenAPIV3.Document, options: GeneratorOptions): st generateBlockComment('ENUMS', generateStatements(...[...enums.values()].map((v) => v.source))), generateBlockComment('ENTITIES', generateStatements(...[...entities.values()].map((v) => v.source))), generateBlockComment('FILTERS', generateStatements(...[...entities.values()].map((v) => v.filterSource))), - generateBlockComment('SERVICES', generateStatements(...[...services.values()].map((v) => v.source))), + generateBlockComment( + 'SERVICES', + generateStatements(generateReferencedEntities(entities), ...[...services.values()].map((v) => v.source)) + ), generateBlockComment('MAPS', maps) ); }; From 6eaf57d668a9546249f89e737d2b2ecb95cb1532 Mon Sep 17 00:00:00 2001 From: Olivier Costi Date: Tue, 10 Mar 2026 12:58:14 +0100 Subject: [PATCH 3/6] feat: add flatten function for inlcluded referenced entities --- .../01-base/static/queriesWithFilter.ts.txt | 4 ++-- .../static/queriesWithQueryLanguage.ts.txt | 4 ++-- src/generator/01-base/static/types.ts.txt | 8 ++++++++ src/generator/01-base/static/utils.ts.txt | 16 ++++++++++++++++ src/generator/04-services/endpoints/some.ts | 2 -- 5 files changed, 28 insertions(+), 6 deletions(-) diff --git a/src/generator/01-base/static/queriesWithFilter.ts.txt b/src/generator/01-base/static/queriesWithFilter.ts.txt index cfbdea3..0b2964d 100644 --- a/src/generator/01-base/static/queriesWithFilter.ts.txt +++ b/src/generator/01-base/static/queriesWithFilter.ts.txt @@ -37,7 +37,7 @@ export type CountQuery = { export type SomeQuery = { serializeNulls?: boolean; - include?: QuerySelect; + include?: QuerySelectIncludedReferences; properties?: P; filter?: QueryFilter & CustomAttributeFilter; select?: QuerySelect; @@ -171,7 +171,7 @@ const _some = ( serializeNulls: query?.serializeNulls, additionalProperties: query?.properties?.join(','), properties: query?.select ? flattenSelect(query.select).join(',') : undefined, - includeReferencedEntities: query?.include ? Object.keys(query.include).join(',') : undefined, + includeReferencedEntities: query?.include ? flattenIncludedReferences(query.include).join(',') : undefined, ...flattenOrFilter(query?.or), ...flattenFilter(query?.filter), ...flattenSort(query?.sort), diff --git a/src/generator/01-base/static/queriesWithQueryLanguage.ts.txt b/src/generator/01-base/static/queriesWithQueryLanguage.ts.txt index fe0a93f..4784799 100644 --- a/src/generator/01-base/static/queriesWithQueryLanguage.ts.txt +++ b/src/generator/01-base/static/queriesWithQueryLanguage.ts.txt @@ -47,7 +47,7 @@ export type CountQuery = { export type SomeQuery = { serializeNulls?: boolean; - include?: QuerySelect; + include?: QuerySelectIncludedReferences; properties?: P; where?: QueryFilter; select?: QuerySelect; @@ -234,7 +234,7 @@ const _some = ( ? flattenSelect(query.select).join(',') : undefined, includeReferencedEntities: query?.include - ? Object.keys(query.include).join(',') + ? flattenIncludedReferences(query.include).join(',') : undefined, ...assembleFilterParam(query?.where), ...flattenSort(query?.sort), diff --git a/src/generator/01-base/static/types.ts.txt b/src/generator/01-base/static/types.ts.txt index 2e5e7e8..4cd3746 100644 --- a/src/generator/01-base/static/types.ts.txt +++ b/src/generator/01-base/static/types.ts.txt @@ -30,6 +30,14 @@ export type QuerySelect = { : boolean; }; +export type QuerySelectIncludedReferences = { + [P in keyof T]?: T[P] extends Array | undefined + ? QuerySelectIncludedReferences + : T[P] extends Record | undefined + ? QuerySelectIncludedReferences + : boolean; +}; + export type Select | undefined> = Q extends QuerySelect ? { diff --git a/src/generator/01-base/static/utils.ts.txt b/src/generator/01-base/static/utils.ts.txt index 42b9a75..fc66caa 100644 --- a/src/generator/01-base/static/utils.ts.txt +++ b/src/generator/01-base/static/utils.ts.txt @@ -12,6 +12,22 @@ const flattenSelect = (obj: Select = {}): string[] => { return entries; }; +const flattenIncludedReferences = (obj: QuerySelectIncludedReferences = {}, base = ''): string[] => { + const entries: string[] = []; + + for (const [prop, value] of Object.entries(obj)) { + const path = base ? `${base}.${prop}` : prop; + + if (typeof value === 'object' && value) { + entries.push(...flattenIncludedReferences(value as QuerySelectIncludedReferences, path)); + } else if (value) { + entries.push(path); + } + } + + return entries; +}; + export const flattenSort = (obj: Sort[] = []): { sort?: string } => { const flatten = (obj: Sort, base = ''): string | undefined => { const [key, value] = Object.entries(obj ?? {})[0] ?? []; diff --git a/src/generator/04-services/endpoints/some.ts b/src/generator/04-services/endpoints/some.ts index c3a1d30..97af6ef 100644 --- a/src/generator/04-services/endpoints/some.ts +++ b/src/generator/04-services/endpoints/some.ts @@ -98,8 +98,6 @@ const resolveArrayReferenceProperties = ( return properties; }; -// TODO: check v1 and v2 -// TODO: remove boolean from arrays in QuerySelect const resolveReferences = (entity: string, entities: Map) => { const references: InterfaceProperty[] = []; const generatedEntity = entities.get(entity); From c8fb0b8fbbf3dc97eb05583017abb7b0ad3f524b Mon Sep 17 00:00:00 2001 From: Olivier Costi Date: Thu, 26 Mar 2026 08:05:51 +0100 Subject: [PATCH 4/6] feat: refine support for includeReferencedEntities --- .../01-base/static/queriesWithFilter.ts.txt | 2 +- .../static/queriesWithQueryLanguage.ts.txt | 2 +- src/generator/01-base/static/types.ts.txt | 6 ++-- src/generator/01-base/static/utils.ts.txt | 4 +-- src/generator/03-entities/index.ts | 36 ++++++++++--------- src/generator/04-services/endpoints/some.ts | 2 ++ src/generator/generate.ts | 6 ++-- 7 files changed, 31 insertions(+), 27 deletions(-) diff --git a/src/generator/01-base/static/queriesWithFilter.ts.txt b/src/generator/01-base/static/queriesWithFilter.ts.txt index 0b2964d..f3bb46c 100644 --- a/src/generator/01-base/static/queriesWithFilter.ts.txt +++ b/src/generator/01-base/static/queriesWithFilter.ts.txt @@ -37,7 +37,7 @@ export type CountQuery = { export type SomeQuery = { serializeNulls?: boolean; - include?: QuerySelectIncludedReferences; + include?: QueryInclude; properties?: P; filter?: QueryFilter & CustomAttributeFilter; select?: QuerySelect; diff --git a/src/generator/01-base/static/queriesWithQueryLanguage.ts.txt b/src/generator/01-base/static/queriesWithQueryLanguage.ts.txt index 8b9039b..6769f5c 100644 --- a/src/generator/01-base/static/queriesWithQueryLanguage.ts.txt +++ b/src/generator/01-base/static/queriesWithQueryLanguage.ts.txt @@ -74,7 +74,7 @@ export type CountQuery = { export type SomeQuery = { serializeNulls?: boolean; - include?: QuerySelectIncludedReferences; + include?: QueryInclude; properties?: P; where?: QueryFilter; select?: QuerySelect; diff --git a/src/generator/01-base/static/types.ts.txt b/src/generator/01-base/static/types.ts.txt index 4cd3746..c192314 100644 --- a/src/generator/01-base/static/types.ts.txt +++ b/src/generator/01-base/static/types.ts.txt @@ -30,11 +30,11 @@ export type QuerySelect = { : boolean; }; -export type QuerySelectIncludedReferences = { +export type QueryInclude = { [P in keyof T]?: T[P] extends Array | undefined - ? QuerySelectIncludedReferences + ? QueryInclude : T[P] extends Record | undefined - ? QuerySelectIncludedReferences + ? QueryInclude : boolean; }; diff --git a/src/generator/01-base/static/utils.ts.txt b/src/generator/01-base/static/utils.ts.txt index fc66caa..8fb9246 100644 --- a/src/generator/01-base/static/utils.ts.txt +++ b/src/generator/01-base/static/utils.ts.txt @@ -12,14 +12,14 @@ const flattenSelect = (obj: Select = {}): string[] => { return entries; }; -const flattenIncludedReferences = (obj: QuerySelectIncludedReferences = {}, base = ''): string[] => { +const flattenIncludedReferences = (obj: QueryInclude = {}, base = ''): string[] => { const entries: string[] = []; for (const [prop, value] of Object.entries(obj)) { const path = base ? `${base}.${prop}` : prop; if (typeof value === 'object' && value) { - entries.push(...flattenIncludedReferences(value as QuerySelectIncludedReferences, path)); + entries.push(...flattenIncludedReferences(value as QueryInclude, path)); } else if (value) { entries.push(path); } diff --git a/src/generator/03-entities/index.ts b/src/generator/03-entities/index.ts index cf0cfec..a54bc17 100644 --- a/src/generator/03-entities/index.ts +++ b/src/generator/03-entities/index.ts @@ -23,13 +23,6 @@ export interface GeneratedEntity { export const FILTER_PROPS_SUFFIX = 'Filter_Props'; -const excludedReferencedEntities = new Set([ - 'abstractParty', - 'abstractEntity', - 'abstractEntityWithCustomAttributes', - 'onlyId' -]); - export const generateEntities = (context: OpenApiContext): Map => { const entities: Map = new Map(); @@ -152,13 +145,24 @@ export const generateEntities = (context: OpenApiContext): Map) => { - const referencedEntities = [...entities.values()] - .filter((entity) => !excludedReferencedEntities.has(entity.name)) - .map((entity) => ({ - name: entity.name, - type: `${entity.interfaceName}[]` - })); - - return generateInterfaceType('ReferencedEntities', referencedEntities); +export const generateReferencedEntities = (entities: Map, aliases: Map) => { + const aliasKeys = new Set(aliases.keys()); + + return generateInterfaceType( + 'ReferencedEntities', + [ + ...[...entities.values()] + .filter((entity) => aliasKeys.has(entity.name)) + .map((entity) => ({ + name: entity.name, + type: `${entity.interfaceName}[]` + })), + ...[...aliases.entries()] + .filter(([, alias]) => loosePascalCase(alias) === 'CustomValue') + .map(([entityName]) => ({ + name: entityName, + type: 'CustomValue[]' + })) + ].sort((a, b) => a.name.localeCompare(b.name)) + ); }; diff --git a/src/generator/04-services/endpoints/some.ts b/src/generator/04-services/endpoints/some.ts index 685cb70..a55c37c 100644 --- a/src/generator/04-services/endpoints/some.ts +++ b/src/generator/04-services/endpoints/some.ts @@ -108,6 +108,8 @@ const resolveReferences = (entity: string, entities: Map v.source))), generateBlockComment('ENTITIES', generateStatements(...[...entities.values()].map((v) => v.source))), generateBlockComment('FILTERS', generateStatements(...[...entities.values()].map((v) => v.filterSource))), - generateBlockComment( - 'SERVICES', - generateStatements(generateReferencedEntities(entities), ...[...services.values()].map((v) => v.source)) - ), + generateBlockComment('REFERENCED ENTITIES', generateReferencedEntities(entities, context.aliases)), + generateBlockComment('SERVICES', generateStatements(...[...services.values()].map((v) => v.source))), generateBlockComment('MAPS', maps) ); }; From 3f17115768475b2c80d3f19262cf0e7090ce2616 Mon Sep 17 00:00:00 2001 From: Olivier Costi Date: Fri, 10 Apr 2026 09:21:19 +0200 Subject: [PATCH 5/6] breaking: remove QueryInclude --- .../01-base/static/queriesWithFilter.ts.txt | 2 +- .../01-base/static/queriesWithQueryLanguage.ts.txt | 2 +- src/generator/01-base/static/types.ts.txt | 8 -------- src/generator/01-base/static/utils.ts.txt | 4 ++-- src/generator/04-services/endpoints/some.ts | 13 +++++-------- 5 files changed, 9 insertions(+), 20 deletions(-) diff --git a/src/generator/01-base/static/queriesWithFilter.ts.txt b/src/generator/01-base/static/queriesWithFilter.ts.txt index f3bb46c..6d5b609 100644 --- a/src/generator/01-base/static/queriesWithFilter.ts.txt +++ b/src/generator/01-base/static/queriesWithFilter.ts.txt @@ -37,7 +37,7 @@ export type CountQuery = { export type SomeQuery = { serializeNulls?: boolean; - include?: QueryInclude; + include?: I; properties?: P; filter?: QueryFilter & CustomAttributeFilter; select?: QuerySelect; diff --git a/src/generator/01-base/static/queriesWithQueryLanguage.ts.txt b/src/generator/01-base/static/queriesWithQueryLanguage.ts.txt index 6769f5c..44e2a01 100644 --- a/src/generator/01-base/static/queriesWithQueryLanguage.ts.txt +++ b/src/generator/01-base/static/queriesWithQueryLanguage.ts.txt @@ -74,7 +74,7 @@ export type CountQuery = { export type SomeQuery = { serializeNulls?: boolean; - include?: QueryInclude; + include?: I; properties?: P; where?: QueryFilter; select?: QuerySelect; diff --git a/src/generator/01-base/static/types.ts.txt b/src/generator/01-base/static/types.ts.txt index c192314..2e5e7e8 100644 --- a/src/generator/01-base/static/types.ts.txt +++ b/src/generator/01-base/static/types.ts.txt @@ -30,14 +30,6 @@ export type QuerySelect = { : boolean; }; -export type QueryInclude = { - [P in keyof T]?: T[P] extends Array | undefined - ? QueryInclude - : T[P] extends Record | undefined - ? QueryInclude - : boolean; -}; - export type Select | undefined> = Q extends QuerySelect ? { diff --git a/src/generator/01-base/static/utils.ts.txt b/src/generator/01-base/static/utils.ts.txt index 8fb9246..081f4d7 100644 --- a/src/generator/01-base/static/utils.ts.txt +++ b/src/generator/01-base/static/utils.ts.txt @@ -12,14 +12,14 @@ const flattenSelect = (obj: Select = {}): string[] => { return entries; }; -const flattenIncludedReferences = (obj: QueryInclude = {}, base = ''): string[] => { +const flattenIncludedReferences = (obj: Record = {}, base = ''): string[] => { const entries: string[] = []; for (const [prop, value] of Object.entries(obj)) { const path = base ? `${base}.${prop}` : prop; if (typeof value === 'object' && value) { - entries.push(...flattenIncludedReferences(value as QueryInclude, path)); + entries.push(...flattenIncludedReferences(value as Record, path)); } else if (value) { entries.push(path); } diff --git a/src/generator/04-services/endpoints/some.ts b/src/generator/04-services/endpoints/some.ts index a55c37c..3d98888 100644 --- a/src/generator/04-services/endpoints/some.ts +++ b/src/generator/04-services/endpoints/some.ts @@ -68,7 +68,7 @@ const resolveArrayReferenceProperties = ( ([property, propertyMetaData]): ObjectProperty[] => { if (propertyMetaData.type === 'array') { if (propertyMetaData.entity === 'onlyId') { - return [{ key: property, value: [{ key: 'id', value: 'string' }] }]; + return [{ key: property, value: [{ key: 'id', value: 'boolean' }] }]; } if (!propertyMetaData.entity) { @@ -89,7 +89,7 @@ const resolveArrayReferenceProperties = ( } if (property.endsWith('Id')) { - return [{ key: property, value: 'string' }]; + return [{ key: property, value: 'boolean' }]; } return []; @@ -114,16 +114,14 @@ const resolveReferences = (entity: string, entities: Map Date: Fri, 10 Apr 2026 11:12:22 +0200 Subject: [PATCH 6/6] feat: add service check for referenced entities --- src/generator/03-entities/index.ts | 11 ++++++++--- src/generator/generate.ts | 2 +- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/generator/03-entities/index.ts b/src/generator/03-entities/index.ts index a54bc17..8b52b28 100644 --- a/src/generator/03-entities/index.ts +++ b/src/generator/03-entities/index.ts @@ -145,20 +145,25 @@ export const generateEntities = (context: OpenApiContext): Map, aliases: Map) => { +export const generateReferencedEntities = ( + entities: Map, + aliases: Map, + services: Map +) => { const aliasKeys = new Set(aliases.keys()); + const serviceKeys = new Set(services.keys()); return generateInterfaceType( 'ReferencedEntities', [ ...[...entities.values()] - .filter((entity) => aliasKeys.has(entity.name)) + .filter((entity) => aliasKeys.has(entity.name) && serviceKeys.has(entity.name)) .map((entity) => ({ name: entity.name, type: `${entity.interfaceName}[]` })), ...[...aliases.entries()] - .filter(([, alias]) => loosePascalCase(alias) === 'CustomValue') + .filter(([, alias]) => alias === 'customValue') .map(([entityName]) => ({ name: entityName, type: 'CustomValue[]' diff --git a/src/generator/generate.ts b/src/generator/generate.ts index 0aa849f..220a4c4 100644 --- a/src/generator/generate.ts +++ b/src/generator/generate.ts @@ -34,7 +34,7 @@ export const generate = (doc: OpenAPIV3.Document, options: GeneratorOptions): st generateBlockComment('ENUMS', generateStatements(...[...enums.values()].map((v) => v.source))), generateBlockComment('ENTITIES', generateStatements(...[...entities.values()].map((v) => v.source))), generateBlockComment('FILTERS', generateStatements(...[...entities.values()].map((v) => v.filterSource))), - generateBlockComment('REFERENCED ENTITIES', generateReferencedEntities(entities, context.aliases)), + generateBlockComment('REFERENCED ENTITIES', generateReferencedEntities(entities, context.aliases, services)), generateBlockComment('SERVICES', generateStatements(...[...services.values()].map((v) => v.source))), generateBlockComment('MAPS', maps) );