Skip to content

Commit

Permalink
fix(cli): Include plugin options in service constructor
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelbromley committed May 2, 2024
1 parent 40000a4 commit a77251e
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 8 deletions.
37 changes: 30 additions & 7 deletions packages/cli/src/commands/add/service/add-service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { cancel, isCancel, log, select, spinner, text } from '@clack/prompts';
import { paramCase } from 'change-case';
import path from 'path';
import { ClassDeclaration, SourceFile } from 'ts-morph';
import { ClassDeclaration, Scope, SourceFile } from 'ts-morph';

import { Messages, pascalCaseRegex } from '../../../constants';
import { CliCommand, CliCommandReturnVal } from '../../../shared/cli-command';
Expand Down Expand Up @@ -77,13 +77,8 @@ async function addService(
}

const serviceSpinner = spinner();
const serviceFileName = paramCase(options.serviceName).replace(/-service$/, '.service');

let serviceSourceFile: SourceFile;
const serviceSourceFilePath = path.join(
vendurePlugin.getPluginDir().getPath(),
'services',
`${serviceFileName}.ts`,
);
let serviceClassDeclaration: ClassDeclaration;
if (options.type === 'basic') {
const name = await text({
Expand All @@ -106,6 +101,7 @@ async function addService(

options.serviceName = name;
serviceSpinner.start(`Creating ${options.serviceName}...`);
const serviceSourceFilePath = getServiceFilePath(vendurePlugin, options.serviceName);
await pauseForPromptDisplay();
serviceSourceFile = createFile(
project,
Expand All @@ -119,6 +115,7 @@ async function addService(
} else {
serviceSpinner.start(`Creating ${options.serviceName}...`);
await pauseForPromptDisplay();
const serviceSourceFilePath = getServiceFilePath(vendurePlugin, options.serviceName);
serviceSourceFile = createFile(
project,
path.join(__dirname, 'templates/entity-service.template.ts'),
Expand Down Expand Up @@ -163,6 +160,27 @@ async function addService(
customizeUpdateMethod(serviceClassDeclaration, entityRef);
removedUnusedConstructorArgs(serviceClassDeclaration, entityRef);
}
const pluginOptions = vendurePlugin.getPluginOptions();
if (pluginOptions) {
addImportsToFile(serviceSourceFile, {
moduleSpecifier: pluginOptions.constantDeclaration.getSourceFile(),
namedImports: [pluginOptions.constantDeclaration.getName()],
});
addImportsToFile(serviceSourceFile, {
moduleSpecifier: pluginOptions.typeDeclaration.getSourceFile(),
namedImports: [pluginOptions.typeDeclaration.getName()],
});
addImportsToFile(serviceSourceFile, {
moduleSpecifier: '@nestjs/common',
namedImports: ['Inject'],
});
serviceClassDeclaration.getConstructors()[0]?.addParameter({
scope: Scope.Private,
name: 'options',
type: pluginOptions.typeDeclaration.getName(),
decorators: [{ name: 'Inject', arguments: [pluginOptions.constantDeclaration.getName()] }],
});
}
modifiedSourceFiles.push(serviceSourceFile);

serviceSpinner.message(`Registering service with plugin...`);
Expand All @@ -184,6 +202,11 @@ async function addService(
};
}

function getServiceFilePath(plugin: VendurePluginRef, serviceName: string) {
const serviceFileName = paramCase(serviceName).replace(/-service$/, '.service');
return path.join(plugin.getPluginDir().getPath(), 'services', `${serviceFileName}.ts`);
}

function customizeFindOneMethod(serviceClassDeclaration: ClassDeclaration, entityRef: EntityRef) {
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
const findOneMethod = serviceClassDeclaration.getMethod('findOne')!;
Expand Down
51 changes: 50 additions & 1 deletion packages/cli/src/shared/vendure-plugin-ref.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
import { ClassDeclaration, Node, StructureKind, SyntaxKind, VariableDeclaration } from 'ts-morph';
import {
ClassDeclaration,
InterfaceDeclaration,
Node,
PropertyAssignment,
StructureKind,
SyntaxKind,
Type,
VariableDeclaration,
} from 'ts-morph';

import { AdminUiExtensionTypeName } from '../constants';

Expand Down Expand Up @@ -31,6 +40,46 @@ export class VendurePluginRef {
return pluginOptions;
}

getPluginOptions():
| { typeDeclaration: InterfaceDeclaration; constantDeclaration: VariableDeclaration }
| undefined {
const metadataOptions = this.getMetadataOptions();
const staticOptions = this.classDeclaration.getStaticProperty('options');
const typeDeclaration = staticOptions
?.getType()
.getSymbolOrThrow()
.getDeclarations()
.find(d => Node.isInterfaceDeclaration(d));
if (!typeDeclaration || !Node.isInterfaceDeclaration(typeDeclaration)) {
return;
}
const providersArray = metadataOptions
.getProperty('providers')
?.getFirstChildByKind(SyntaxKind.ArrayLiteralExpression);
if (!providersArray) {
return;
}
const elements = providersArray.getElements();
const optionsProviders = elements
.filter(Node.isObjectLiteralExpression)
.filter(el => el.getProperty('useFactory')?.getText().includes(`${this.name}.options`));

if (!optionsProviders.length) {
return;
}
const optionsSymbol = optionsProviders[0].getProperty('provide') as PropertyAssignment;
const initializer = optionsSymbol?.getInitializer();
if (!initializer || !Node.isIdentifier(initializer)) {
return;
}
const constantDeclaration = initializer.getDefinitions()[0]?.getDeclarationNode();
if (!constantDeclaration || !Node.isVariableDeclaration(constantDeclaration)) {
return;
}

return { typeDeclaration, constantDeclaration };
}

addEntity(entityClassName: string) {
const pluginOptions = this.getMetadataOptions();
const entityProperty = pluginOptions.getProperty('entities');
Expand Down

0 comments on commit a77251e

Please sign in to comment.