Skip to content

Commit

Permalink
refactor(cli): Create CodegenConfigRef, various refactors
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelbromley committed Apr 3, 2024
1 parent 342861d commit e18784f
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 40 deletions.
53 changes: 19 additions & 34 deletions packages/cli/src/commands/add/codegen/add-codegen.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { log, note, outro, spinner } from '@clack/prompts';
import path from 'path';
import { ClassDeclaration, StructureKind, SyntaxKind } from 'ts-morph';
import { StructureKind } from 'ts-morph';

import { analyzeProject, selectMultiplePluginClasses } from '../../../shared/shared-prompts';
import { createFile, getRelativeImportPath, getTsMorphProject } from '../../../utilities/ast-utils';
import { getRelativeImportPath } from '../../../utilities/ast-utils';
import { CodegenConfigRef } from '../../../utilities/codegen-config-ref';
import { PackageJson } from '../../../utilities/package-utils';
import { VendurePluginRef } from '../../../utilities/vendure-plugin-ref';

Expand Down Expand Up @@ -46,62 +47,46 @@ export async function addCodegen(providedVendurePlugin?: VendurePluginRef) {
configSpinner.start('Configuring codegen file...');
await new Promise(resolve => setTimeout(resolve, 100));

const tempProject = getTsMorphProject({ skipAddingFilesFromTsConfig: true });
const codegenFile = createFile(tempProject, path.join(__dirname, 'templates/codegen.template.ts'));
const codegenConfig = codegenFile
.getVariableDeclaration('config')
?.getChildrenOfKind(SyntaxKind.ObjectLiteralExpression)[0];
if (!codegenConfig) {
throw new Error('Could not find the config variable in the template codegen file');
}
const generatesProp = codegenConfig
.getProperty('generates')
?.getFirstChildByKind(SyntaxKind.ObjectLiteralExpression);
if (!generatesProp) {
throw new Error('Could not find the generates property in the template codegen file');
}
const rootDir = tempProject.getDirectory('.');
const codegenFile = new CodegenConfigRef(packageJson.getPackageRootDir());

const rootDir = project.getDirectory('.');
if (!rootDir) {
throw new Error('Could not find the root directory of the project');
}
for (const plugin of plugins) {
const relativePluginPath = getRelativeImportPath({
from: plugin.classDeclaration.getSourceFile(),
to: rootDir,
from: rootDir,
to: plugin.classDeclaration.getSourceFile(),
});
const generatedTypesPath = `${path.dirname(relativePluginPath)}/gql/generated.ts`;
generatesProp
.addProperty({
name: `'${generatedTypesPath}'`,
kind: StructureKind.PropertyAssignment,
initializer: `{ plugins: ['typescript'] }`,
})
.formatText();
codegenFile.addEntryToGeneratesObject({
name: `'${generatedTypesPath}'`,
kind: StructureKind.PropertyAssignment,
initializer: `{ plugins: ['typescript'] }`,
});

if (plugin.hasUiExtensions()) {
const uiExtensionsPath = `${path.dirname(relativePluginPath)}/ui`;
generatesProp
.addProperty({
name: `'${uiExtensionsPath}/gql/'`,
kind: StructureKind.PropertyAssignment,
initializer: `{
codegenFile.addEntryToGeneratesObject({
name: `'${uiExtensionsPath}/gql/'`,
kind: StructureKind.PropertyAssignment,
initializer: `{
preset: 'client',
documents: '${uiExtensionsPath}/**/*.ts',
presetConfig: {
fragmentMasking: false,
},
}`,
})
.formatText();
});
}
}
codegenFile.move(path.join(rootDir.getPath(), 'codegen.ts'));

packageJson.addScript('codegen', 'graphql-codegen --config codegen.ts');

configSpinner.stop('Configured codegen file');

await project.save();
await codegenFile.save();

const nextSteps = [
`You can run codegen by doing the following:`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ export async function addUiExtensions(providedVendurePlugin?: VendurePluginRef)
} else {
const pluginClassName = vendurePlugin.name;
const pluginPath = getRelativeImportPath({
to: vendureConfig.sourceFile,
from: vendurePlugin.classDeclaration.getSourceFile(),
to: vendurePlugin.classDeclaration.getSourceFile(),
from: vendureConfig.sourceFile,
});
const updated = updateAdminUiPluginInit(vendureConfig, { pluginClassName, pluginPath });
if (updated) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { Node, ObjectLiteralExpression, StructureKind, SyntaxKind } from 'ts-morph';

import { AdminUiAppConfigName } from '../../../../../constants';
import { addImportsToFile } from '../../../../../utilities/ast-utils';
import { VendureConfigRef } from '../../../../../utilities/vendure-config-ref';

Expand Down Expand Up @@ -34,7 +35,7 @@ export function updateAdminUiPluginInit(
.formatText();
} else {
const computeFnCall = appProperty.getFirstChildByKind(SyntaxKind.CallExpression);
if (computeFnCall?.getType().getText().includes('AdminUiAppConfig')) {
if (computeFnCall?.getType().getSymbol()?.getName() === AdminUiAppConfigName) {
const arg = computeFnCall.getArguments()[0];
if (arg && Node.isObjectLiteralExpression(arg)) {
const extensionsProp = arg.getProperty('extensions');
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export const defaultManipulationSettings: Partial<ManipulationSettings> = {
};

export const AdminUiExtensionTypeName = 'AdminUiExtension';
export const AdminUiAppConfigName = 'AdminUiAppConfig';
export const Messages = {
NoPluginsFound: `No plugins were found in this project. Create a plugin first by selecting "[Plugin] Add a new plugin"`,
};
3 changes: 2 additions & 1 deletion packages/cli/src/utilities/ast-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,8 @@ export function getRelativeImportPath(locations: {
const fromPath =
locations.from instanceof SourceFile ? locations.from.getFilePath() : locations.from.getPath();
const toPath = locations.to instanceof SourceFile ? locations.to.getFilePath() : locations.to.getPath();
return convertPathToRelativeImport(path.relative(path.dirname(fromPath), toPath));
const fromDir = /\.[a-z]+$/.test(fromPath) ? path.dirname(fromPath) : fromPath;
return convertPathToRelativeImport(path.relative(fromDir, toPath));
}

export function createFile(project: Project, templatePath: string) {
Expand Down
63 changes: 63 additions & 0 deletions packages/cli/src/utilities/codegen-config-ref.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import fs from 'fs-extra';
import path from 'path';
import {
Directory,
ObjectLiteralExpression,
ObjectLiteralExpressionPropertyStructures,
Project,
PropertyAssignmentStructure,
SourceFile,
SyntaxKind,
} from 'ts-morph';

import { createFile, getTsMorphProject } from './ast-utils';

export class CodegenConfigRef {
private readonly tempProject: Project;
private readonly sourceFile: SourceFile;
private configObject: ObjectLiteralExpression | undefined;
constructor(rootDir: Directory) {
this.tempProject = getTsMorphProject({ skipAddingFilesFromTsConfig: true });
const codegenFilePath = path.join(rootDir.getPath(), 'codegen.ts');
if (fs.existsSync(codegenFilePath)) {
this.sourceFile = this.tempProject.addSourceFileAtPath(codegenFilePath);
} else {
this.sourceFile = createFile(
this.tempProject,
path.join(__dirname, 'templates/codegen.template.ts'),
);
this.sourceFile.move(path.join(rootDir.getPath(), 'codegen.ts'));
}
}

addEntryToGeneratesObject(structure: PropertyAssignmentStructure) {
const generatesProp = this.getConfigObject()
.getProperty('generates')
?.getFirstChildByKind(SyntaxKind.ObjectLiteralExpression);
if (!generatesProp) {
throw new Error('Could not find the generates property in the template codegen file');
}
if (generatesProp.getProperty(structure.name)) {
return;
}
generatesProp.addProperty(structure).formatText();
}

getConfigObject() {
if (this.configObject) {
return this.configObject;
}
const codegenConfig = this.sourceFile
.getVariableDeclaration('config')
?.getChildrenOfKind(SyntaxKind.ObjectLiteralExpression)[0];
if (!codegenConfig) {
throw new Error('Could not find the config variable in the template codegen file');
}
this.configObject = codegenConfig;
return this.configObject;
}

save() {
return this.tempProject.save();
}
}
2 changes: 1 addition & 1 deletion packages/cli/src/utilities/package-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export class PackageJson {
fs.writeJsonSync(packageJsonPath, packageJson, { spaces: 2 });
}

private getPackageRootDir() {
getPackageRootDir() {
const rootDir = this.project.getDirectory('.');
if (!rootDir) {
throw new Error('Could not find the root directory of the project');
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/utilities/vendure-plugin-ref.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@ export class VendurePluginRef {
hasUiExtensions(): boolean {
return !!this.classDeclaration
.getStaticProperties()
.find(prop => prop.getType().getText() === AdminUiExtensionTypeName);
.find(prop => prop.getType().getSymbol()?.getName() === AdminUiExtensionTypeName);
}
}

0 comments on commit e18784f

Please sign in to comment.