From d5c95602c104b3ef2b949fcc077e310417e2c246 Mon Sep 17 00:00:00 2001 From: dsinghvi Date: Tue, 12 Nov 2024 09:57:39 -0500 Subject: [PATCH 1/6] fix(ruby): tweak generation --- .github/workflows/publish-ruby-sdk.yml | 46 ++++++++++++++++++++++ generators/ruby/codegen/src/ast/Module_.ts | 31 ++++++++------- generators/ruby/sdk/Dockerfile | 4 +- 3 files changed, 65 insertions(+), 16 deletions(-) create mode 100644 .github/workflows/publish-ruby-sdk.yml diff --git a/.github/workflows/publish-ruby-sdk.yml b/.github/workflows/publish-ruby-sdk.yml new file mode 100644 index 00000000000..51f77789d8b --- /dev/null +++ b/.github/workflows/publish-ruby-sdk.yml @@ -0,0 +1,46 @@ +on: + push: + branches: + - dsinghvi/ruby-tweaks + +jobs: + ruby-sdk: + runs-on: ubuntu-latest + steps: + - name: Checkout repo + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: actions/setup-node@v3 + with: + node-version: 18 + cache: "yarn" + + - name: Log in to Docker Hub + uses: docker/login-action@v3 + with: + username: fernapi + password: ${{ secrets.FERN_API_DOCKERHUB_PASSWORD }} + + - name: Install + run: yarn install + + - name: Build CLI + working-directory: ./generators/ruby/sdk + run: yarn dist:cli + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + + - name: Build and push Docker image + uses: docker/build-push-action@v2 + with: + context: . + file: ./generators/ruby/sdk/Dockerfile + platforms: linux/amd64,linux/arm64 + cache-from: type=gha + cache-to: type=gha,mode=min + push: true + labels: version=0.9.0-rc0 + tags: fernapi/fern-ruby-sdk:0.9.0-rc0 diff --git a/generators/ruby/codegen/src/ast/Module_.ts b/generators/ruby/codegen/src/ast/Module_.ts index 82287134609..ad5c9df3e97 100644 --- a/generators/ruby/codegen/src/ast/Module_.ts +++ b/generators/ruby/codegen/src/ast/Module_.ts @@ -52,21 +52,24 @@ export class Module_ extends AstNode { let moduleWrappedItem: Module_ | Class_ | T = child; let moduleBreadcrumbs: string[] = [locationGenerator.rootModule]; if (path) { - if (!locationGenerator.shouldFlattenModules) { - moduleBreadcrumbs = moduleBreadcrumbs.concat(locationGenerator.getModulePathFromTypeName(path)); - const classWrapper = locationGenerator.getClassPathFromTypeName(path); - - if (classWrapper !== undefined && includeFilename) { - moduleWrappedItem = new Class_({ - classReference: new ClassReference({ name: classWrapper }), - includeInitializer: false, - children: child - }); - } - } else { - moduleBreadcrumbs = locationGenerator.getModuleBreadcrumbs({ path, includeFilename, isType }); - } + moduleBreadcrumbs = locationGenerator.getModuleBreadcrumbs({ path, includeFilename, isType }); } + // if (path) { + // if (!locationGenerator.shouldFlattenModules) { + // moduleBreadcrumbs = moduleBreadcrumbs.concat(locationGenerator.getModulePathFromTypeName(path)); + // const classWrapper = locationGenerator.getClassPathFromTypeName(path); + + // if (classWrapper !== undefined && includeFilename) { + // moduleWrappedItem = new Class_({ + // classReference: new ClassReference({ name: classWrapper }), + // includeInitializer: false, + // children: child + // }); + // } + // } else { + // moduleBreadcrumbs = locationGenerator.getModuleBreadcrumbs({ path, includeFilename, isType }); + // } + // } moduleBreadcrumbs.reverse().forEach( (mod) => diff --git a/generators/ruby/sdk/Dockerfile b/generators/ruby/sdk/Dockerfile index b63f95fc108..9f0ca7f9364 100644 --- a/generators/ruby/sdk/Dockerfile +++ b/generators/ruby/sdk/Dockerfile @@ -1,9 +1,9 @@ # syntax = edrevo/dockerfile-plus INCLUDE+ packages/generators/docker/Dockerfile.base -COPY generators/ruby/sdk/dist /dist - # Install Ruby and Rubocop for formatting RUN apk update && apk add --no-cache build-base ruby ruby-dev && gem install rubocop +COPY generators/ruby/sdk/dist /dist + ENTRYPOINT ["node", "/dist/cli.cjs", "ruby-sdk"] \ No newline at end of file From 4b09e10af073bb54dd021c98fe2ded6e55378ab9 Mon Sep 17 00:00:00 2001 From: dsinghvi Date: Tue, 12 Nov 2024 10:11:04 -0500 Subject: [PATCH 2/6] try again --- .github/workflows/publish-ruby-sdk.yml | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/.github/workflows/publish-ruby-sdk.yml b/.github/workflows/publish-ruby-sdk.yml index 51f77789d8b..294f47ba2ec 100644 --- a/.github/workflows/publish-ruby-sdk.yml +++ b/.github/workflows/publish-ruby-sdk.yml @@ -10,12 +10,10 @@ jobs: - name: Checkout repo uses: actions/checkout@v4 with: - fetch-depth: 0 + fetch-tags: true - - uses: actions/setup-node@v3 - with: - node-version: 18 - cache: "yarn" + - name: 📥 Install + uses: ./.github/actions/install - name: Log in to Docker Hub uses: docker/login-action@v3 @@ -23,12 +21,8 @@ jobs: username: fernapi password: ${{ secrets.FERN_API_DOCKERHUB_PASSWORD }} - - name: Install - run: yarn install - - name: Build CLI - working-directory: ./generators/ruby/sdk - run: yarn dist:cli + run: pnpm --filter @fern-api/fern-ruby-sdk dist:cli - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 From d3f3cf744a06be801ec46d53ef6d24ddb00b1f17 Mon Sep 17 00:00:00 2001 From: dsinghvi Date: Tue, 12 Nov 2024 10:24:42 -0500 Subject: [PATCH 3/6] try again --- .github/workflows/publish-ruby-sdk.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publish-ruby-sdk.yml b/.github/workflows/publish-ruby-sdk.yml index 294f47ba2ec..d11e4dcf4a4 100644 --- a/.github/workflows/publish-ruby-sdk.yml +++ b/.github/workflows/publish-ruby-sdk.yml @@ -33,8 +33,8 @@ jobs: context: . file: ./generators/ruby/sdk/Dockerfile platforms: linux/amd64,linux/arm64 - cache-from: type=gha - cache-to: type=gha,mode=min + # cache-from: type=gha + # cache-to: type=gha,mode=min push: true labels: version=0.9.0-rc0 tags: fernapi/fern-ruby-sdk:0.9.0-rc0 From 2595572ad33f17a96b8db1e212865628586e1196 Mon Sep 17 00:00:00 2001 From: dsinghvi Date: Fri, 15 Nov 2024 11:10:16 -0500 Subject: [PATCH 4/6] fix more bugs around subpackage client references + speed up docker build --- generators/ruby/sdk/Dockerfile | 20 +++- .../ruby/sdk/src/AbstractionUtilities.ts | 108 +++++++++++++++--- generators/ruby/sdk/src/ClientsGenerator.ts | 60 +++++++--- generators/ruby/sdk/src/GeneratorCli.ts | 40 +++---- 4 files changed, 173 insertions(+), 55 deletions(-) diff --git a/generators/ruby/sdk/Dockerfile b/generators/ruby/sdk/Dockerfile index 9f0ca7f9364..206a7ab37b0 100644 --- a/generators/ruby/sdk/Dockerfile +++ b/generators/ruby/sdk/Dockerfile @@ -1,9 +1,19 @@ -# syntax = edrevo/dockerfile-plus -INCLUDE+ packages/generators/docker/Dockerfile.base +FROM node:20.18-alpine3.20 AS node +FROM ruby:3.2.6-alpine3.20 -# Install Ruby and Rubocop for formatting -RUN apk update && apk add --no-cache build-base ruby ruby-dev && gem install rubocop +RUN apk --no-cache add bash curl git zip && git config --global user.name "fern" && git config --global user.email "hey@buildwithfern.com" + +RUN curl -L https://cs.symfony.com/download/php-cs-fixer-v3.phar -o /usr/local/bin/php-cs-fixer \ + && chmod +x /usr/local/bin/php-cs-fixer +ENV YARN_CACHE_FOLDER=/.yarn COPY generators/ruby/sdk/dist /dist -ENTRYPOINT ["node", "/dist/cli.cjs", "ruby-sdk"] \ No newline at end of file +# Copy over node contents to be able to run the compiled CLI +COPY --from=node /usr/local/bin/node /usr/local/bin/ +COPY --from=node /usr/local/lib/node_modules /usr/local/lib/node_modules +RUN ln -s ../lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npm \ + && ln -s ../lib/node_modules/npm/bin/npx-cli.js /usr/local/bin/npx + +# Cache generator files and create entry point within an extended Dockerfile +ENTRYPOINT ["node", "/dist/cli.cjs"] diff --git a/generators/ruby/sdk/src/AbstractionUtilities.ts b/generators/ruby/sdk/src/AbstractionUtilities.ts index 0d854da2364..09c8a8f3830 100644 --- a/generators/ruby/sdk/src/AbstractionUtilities.ts +++ b/generators/ruby/sdk/src/AbstractionUtilities.ts @@ -569,7 +569,9 @@ export function generateService( fileUploadUtility: FileUploadUtility, locationGenerator: LocationGenerator, packagePath: string[], - artifactRegistry: ArtifactRegistry + artifactRegistry: ArtifactRegistry, + subpackages: Map = new Map(), + asyncSubpackages: Map = new Map() ): ClientClassPair { const subpackageName = subpackage.name; const serviceName = subpackageName.pascalCase.unsafeName; @@ -587,14 +589,21 @@ export function generateService( import_, moduleBreadcrumbs }); + const syncClassReference = new ClassReference({ + name: `${serviceName}Client`, + import_, + moduleBreadcrumbs + }); const syncClientClass = new Class_({ - classReference: new ClassReference({ - name: `${serviceName}Client`, - import_, - moduleBreadcrumbs - }), - properties: [requestClientProperty], - includeInitializer: true, + classReference: syncClassReference, + properties: [ + requestClientProperty, + ...Array.from(subpackages.entries()).map( + ([spName, sp]) => + new Property({ name: getSubpackagePropertyNameFromIr(spName), type: sp.classReference }) + ) + ], + includeInitializer: false, functions: generateEndpoints( crf, eg, @@ -611,19 +620,55 @@ export function generateService( packagePath, syncClientClassReference, artifactRegistry - ) + ), + initializerOverride: new Function_({ + name: "initialize", + invocationName: "new", + // Initialize each subpackage + functionBody: Array.from(subpackages.entries()).map(([spName, sp]) => { + const subpackageClassVariable = new Variable({ + name: getSubpackagePropertyNameFromIr(spName), + type: sp.classReference, + variableType: VariableType.INSTANCE + }); + return new Expression({ + leftSide: subpackageClassVariable, + rightSide: + sp.initializer !== undefined + ? new FunctionInvocation({ + onObject: sp.classReference, + baseFunction: sp.initializer, + arguments_: sp.initializer.parameters.map((param) => + param.toArgument(requestClientProperty.toVariable(VariableType.LOCAL)) + ) + }) + : sp.classReference, + isAssignment: true + }); + }), + parameters: [requestClientProperty.toParameter({})], + returnValue: syncClassReference, + documentation: subpackage.docs + }) }); // Add Async Client class const asyncRequestClientProperty = new Property({ name: "request_client", type: asyncRequestClientCr }); + const asyncClassReference = new ClassReference({ + name: `Async${serviceName}Client`, + import_, + moduleBreadcrumbs + }); const asyncClientClass = new Class_({ - classReference: new ClassReference({ - name: `Async${serviceName}Client`, - import_, - moduleBreadcrumbs - }), - properties: [asyncRequestClientProperty], - includeInitializer: true, + classReference: asyncClassReference, + properties: [ + asyncRequestClientProperty, + ...Array.from(subpackages.entries()).map( + ([spName, sp]) => + new Property({ name: getSubpackagePropertyNameFromIr(spName), type: sp.classReference }) + ) + ], + includeInitializer: false, functions: generateEndpoints( crf, eg, @@ -640,7 +685,36 @@ export function generateService( packagePath, undefined, undefined - ) + ), + initializerOverride: new Function_({ + name: "initialize", + invocationName: "new", + // Initialize each subpackage + functionBody: Array.from(asyncSubpackages.entries()).map(([spName, sp]) => { + const subpackageClassVariable = new Variable({ + name: getSubpackagePropertyNameFromIr(spName), + type: sp.classReference, + variableType: VariableType.INSTANCE + }); + return new Expression({ + leftSide: subpackageClassVariable, + rightSide: + sp.initializer !== undefined + ? new FunctionInvocation({ + onObject: sp.classReference, + baseFunction: sp.initializer, + arguments_: sp.initializer.parameters.map((param) => + param.toArgument(asyncRequestClientProperty.toVariable(VariableType.LOCAL)) + ) + }) + : sp.classReference, + isAssignment: true + }); + }), + parameters: [requestClientProperty.toParameter({})], + returnValue: asyncClassReference, + documentation: subpackage.docs + }) }); return { subpackageName, syncClientClass, asyncClientClass }; diff --git a/generators/ruby/sdk/src/ClientsGenerator.ts b/generators/ruby/sdk/src/ClientsGenerator.ts index 087571cd330..2ce451d8e61 100644 --- a/generators/ruby/sdk/src/ClientsGenerator.ts +++ b/generators/ruby/sdk/src/ClientsGenerator.ts @@ -111,7 +111,7 @@ export class ClientsGenerator { if (classReferenceFactory !== undefined) { this.crf = classReferenceFactory; } else { - this.gc.logger.warn("[Ruby] Client generator was not provided a ClassReferenceFactory, regenerating one."); + this.gc.logger.warn("Client generator was not provided a ClassReferenceFactory, regenerating one."); const types = new Map(); for (const type of Object.values(intermediateRepresentation.types)) { types.set(type.name.typeId, type); @@ -156,7 +156,7 @@ export class ClientsGenerator { let environmentClass: Class_ | undefined; if (this.intermediateRepresentation.environments !== undefined) { - this.gc.logger.debug("[Ruby] Preparing environment files."); + this.gc.logger.debug("Preparing environment files."); this.defaultEnvironment = getDefaultEnvironmentUrl( this.clientName, this.intermediateRepresentation.environments @@ -178,7 +178,7 @@ export class ClientsGenerator { ); } - this.gc.logger.debug("[Ruby] Preparing authorization headers."); + this.gc.logger.debug("Preparing authorization headers."); const headersGenerator = new HeadersGenerator( this.intermediateRepresentation.headers, this.crf, @@ -186,7 +186,7 @@ export class ClientsGenerator { this.shouldGenerateOauth ); - this.gc.logger.debug("[Ruby] Preparing request options classes."); + this.gc.logger.debug("Preparing request options classes."); const requestOptionsClass = new RequestOptions({ headersGenerator, clientName: this.clientName @@ -210,7 +210,7 @@ export class ClientsGenerator { isOptional: true }); - this.gc.logger.debug("[Ruby] Preparing request clients."); + this.gc.logger.debug("Preparing request clients."); const [syncClientClass, asyncClientClass] = generateRequestClients( this.clientName, this.intermediateRepresentation.sdkConfig, @@ -237,7 +237,7 @@ export class ClientsGenerator { }) ); - this.gc.logger.debug("[Ruby] Preparing example snippets."); + this.gc.logger.debug("Preparing example snippets."); const dummyRootClientDoNotUse = generateDummyRootClient(this.gemName, this.clientName, syncClientClass); const eg = new ExampleGenerator({ rootClientClass: dummyRootClientDoNotUse, @@ -278,7 +278,9 @@ export class ClientsGenerator { generatedClasses: Map, flattenedProperties: Map, subpackagePaths: Map, - artifactRegistry: ArtifactRegistry + artifactRegistry: ArtifactRegistry, + subpackages: Map = new Map(), + asyncSubpackages: Map = new Map() ): ClientClassPair { if (subpackage.service === undefined) { throw new Error("Calling getServiceClasses without a service defined within the subpackage."); @@ -304,7 +306,9 @@ export class ClientsGenerator { fileUtilityClass, locationGenerator, subpackagePaths.get(packageId) ?? [], - artifactRegistry + artifactRegistry, + subpackages, + asyncSubpackages ); const serviceModule = Module_.wrapInModules({ locationGenerator, @@ -336,7 +340,35 @@ export class ClientsGenerator { subpackagePaths: Map, artifactRegistry: ArtifactRegistry ): ClientClassPair | undefined { - if (subpackage.service !== undefined) { + if (subpackage.service != null) { + const classPairs: ClientClassPair[] = subpackage.subpackages + .map((subpackageId) => { + const subpackage = subpackages.get(subpackageId); + if (subpackage === undefined) { + throw new Error(`Subpackage ${subpackageId} was not defined within in the IR`); + } + + const classPair = subpackageClassReferences.get(subpackageId); + if (classPair === undefined) { + return getSubpackageClasses( + subpackageName, + subpackageId, + subpackage, + services, + subpackages, + clientName, + crf, + irBasePath, + generatedClasses, + flattenedProperties, + subpackagePaths, + artifactRegistry + ); + } + return classPair; + }) + .filter((cp) => cp !== undefined) as ClientClassPair[]; + return getServiceClasses( packageId, subpackage, @@ -347,7 +379,9 @@ export class ClientsGenerator { generatedClasses, flattenedProperties, subpackagePaths, - artifactRegistry + artifactRegistry, + new Map(classPairs.map((cp) => [cp.subpackageName, cp.syncClientClass])), + new Map(classPairs.map((cp) => [cp.subpackageName, cp.asyncClientClass])) ); } else { // We create these subpackage files to support dot access for service clients, @@ -410,7 +444,7 @@ export class ClientsGenerator { } } - this.gc.logger.debug("[Ruby] Generating files for subpackages."); + this.gc.logger.debug("Generating files for subpackages."); Array.from(this.subpackages.entries()).forEach(([packageId, subpackage]) => getSubpackageClasses( subpackage.name, @@ -429,7 +463,7 @@ export class ClientsGenerator { ); // 3. Generate main file, this is what people import while leveraging the gem. - this.gc.logger.debug("[Ruby] Generating files for root package."); + this.gc.logger.debug("Generating files for root package."); const rootSubpackageClasses = this.intermediateRepresentation.rootPackage.subpackages .map((sp) => subpackageClassReferences.get(sp)) .filter((cp) => cp !== undefined) as ClientClassPair[]; @@ -506,7 +540,7 @@ export class ClientsGenerator { ) ); - this.gc.logger.debug("[Ruby] Generating snippets.json file."); + this.gc.logger.debug("Generating snippets.json file."); if (this.gc.config.output.snippetFilepath !== undefined) { clientFiles.push(eg.generateSnippetsFile(this.gc.config.output.snippetFilepath)); } diff --git a/generators/ruby/sdk/src/GeneratorCli.ts b/generators/ruby/sdk/src/GeneratorCli.ts index d18dbd40e99..e1b3e91f104 100644 --- a/generators/ruby/sdk/src/GeneratorCli.ts +++ b/generators/ruby/sdk/src/GeneratorCli.ts @@ -157,11 +157,11 @@ export class RubySdkGeneratorCli extends AbstractGeneratorCli Date: Fri, 15 Nov 2024 11:18:27 -0500 Subject: [PATCH 5/6] publish 0.9.0-rc1 --- .github/workflows/publish-ruby-sdk.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/publish-ruby-sdk.yml b/.github/workflows/publish-ruby-sdk.yml index d11e4dcf4a4..d474784eb3c 100644 --- a/.github/workflows/publish-ruby-sdk.yml +++ b/.github/workflows/publish-ruby-sdk.yml @@ -33,8 +33,8 @@ jobs: context: . file: ./generators/ruby/sdk/Dockerfile platforms: linux/amd64,linux/arm64 - # cache-from: type=gha - # cache-to: type=gha,mode=min + # cache-from: type=gha + # cache-to: type=gha,mode=min push: true - labels: version=0.9.0-rc0 - tags: fernapi/fern-ruby-sdk:0.9.0-rc0 + labels: version=0.9.0-rc1 + tags: fernapi/fern-ruby-sdk:0.9.0-rc1 From e29e5b5d535f3305342db13b9e15e55934e247ac Mon Sep 17 00:00:00 2001 From: dsinghvi Date: Fri, 15 Nov 2024 14:55:49 -0500 Subject: [PATCH 6/6] release 0.9.0-rc2 --- .github/workflows/publish-ruby-sdk.yml | 4 +- .../ruby/sdk/src/AbstractionUtilities.ts | 94 +++++++++++-------- 2 files changed, 56 insertions(+), 42 deletions(-) diff --git a/.github/workflows/publish-ruby-sdk.yml b/.github/workflows/publish-ruby-sdk.yml index d474784eb3c..bb08869b807 100644 --- a/.github/workflows/publish-ruby-sdk.yml +++ b/.github/workflows/publish-ruby-sdk.yml @@ -36,5 +36,5 @@ jobs: # cache-from: type=gha # cache-to: type=gha,mode=min push: true - labels: version=0.9.0-rc1 - tags: fernapi/fern-ruby-sdk:0.9.0-rc1 + labels: version=0.9.0-rc2 + tags: fernapi/fern-ruby-sdk:0.9.0-rc2 diff --git a/generators/ruby/sdk/src/AbstractionUtilities.ts b/generators/ruby/sdk/src/AbstractionUtilities.ts index 09c8a8f3830..7ae89c094c6 100644 --- a/generators/ruby/sdk/src/AbstractionUtilities.ts +++ b/generators/ruby/sdk/src/AbstractionUtilities.ts @@ -625,27 +625,34 @@ export function generateService( name: "initialize", invocationName: "new", // Initialize each subpackage - functionBody: Array.from(subpackages.entries()).map(([spName, sp]) => { - const subpackageClassVariable = new Variable({ - name: getSubpackagePropertyNameFromIr(spName), - type: sp.classReference, - variableType: VariableType.INSTANCE - }); - return new Expression({ - leftSide: subpackageClassVariable, - rightSide: - sp.initializer !== undefined - ? new FunctionInvocation({ - onObject: sp.classReference, - baseFunction: sp.initializer, - arguments_: sp.initializer.parameters.map((param) => - param.toArgument(requestClientProperty.toVariable(VariableType.LOCAL)) - ) - }) - : sp.classReference, + functionBody: [ + new Expression({ + leftSide: requestClientProperty.toVariable(), + rightSide: requestClientProperty.name, isAssignment: true - }); - }), + }), + ...Array.from(subpackages.entries()).map(([spName, sp]) => { + const subpackageClassVariable = new Variable({ + name: getSubpackagePropertyNameFromIr(spName), + type: sp.classReference, + variableType: VariableType.INSTANCE + }); + return new Expression({ + leftSide: subpackageClassVariable, + rightSide: + sp.initializer !== undefined + ? new FunctionInvocation({ + onObject: sp.classReference, + baseFunction: sp.initializer, + arguments_: sp.initializer.parameters.map((param) => + param.toArgument(requestClientProperty.toVariable(VariableType.LOCAL)) + ) + }) + : sp.classReference, + isAssignment: true + }); + }) + ], parameters: [requestClientProperty.toParameter({})], returnValue: syncClassReference, documentation: subpackage.docs @@ -690,27 +697,34 @@ export function generateService( name: "initialize", invocationName: "new", // Initialize each subpackage - functionBody: Array.from(asyncSubpackages.entries()).map(([spName, sp]) => { - const subpackageClassVariable = new Variable({ - name: getSubpackagePropertyNameFromIr(spName), - type: sp.classReference, - variableType: VariableType.INSTANCE - }); - return new Expression({ - leftSide: subpackageClassVariable, - rightSide: - sp.initializer !== undefined - ? new FunctionInvocation({ - onObject: sp.classReference, - baseFunction: sp.initializer, - arguments_: sp.initializer.parameters.map((param) => - param.toArgument(asyncRequestClientProperty.toVariable(VariableType.LOCAL)) - ) - }) - : sp.classReference, + functionBody: [ + new Expression({ + leftSide: requestClientProperty.toVariable(), + rightSide: requestClientProperty.name, isAssignment: true - }); - }), + }), + ...Array.from(asyncSubpackages.entries()).map(([spName, sp]) => { + const subpackageClassVariable = new Variable({ + name: getSubpackagePropertyNameFromIr(spName), + type: sp.classReference, + variableType: VariableType.INSTANCE + }); + return new Expression({ + leftSide: subpackageClassVariable, + rightSide: + sp.initializer !== undefined + ? new FunctionInvocation({ + onObject: sp.classReference, + baseFunction: sp.initializer, + arguments_: sp.initializer.parameters.map((param) => + param.toArgument(asyncRequestClientProperty.toVariable(VariableType.LOCAL)) + ) + }) + : sp.classReference, + isAssignment: true + }); + }) + ], parameters: [requestClientProperty.toParameter({})], returnValue: asyncClassReference, documentation: subpackage.docs