Browse Source

refactor(cli): Create CodegenConfigRef, various refactors

Michael Bromley 1 year ago
parent
commit
e18784f0a6

+ 19 - 34
packages/cli/src/commands/add/codegen/add-codegen.ts

@@ -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';
 
@@ -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:`,

+ 2 - 2
packages/cli/src/commands/add/ui-extensions/add-ui-extensions.ts

@@ -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) {

+ 2 - 1
packages/cli/src/commands/add/ui-extensions/codemods/update-admin-ui-plugin-init/update-admin-ui-plugin-init.ts

@@ -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';
 
@@ -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');

+ 1 - 0
packages/cli/src/constants.ts

@@ -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"`,
 };

+ 2 - 1
packages/cli/src/utilities/ast-utils.ts

@@ -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) {

+ 63 - 0
packages/cli/src/utilities/codegen-config-ref.ts

@@ -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();
+    }
+}

+ 1 - 1
packages/cli/src/utilities/package-utils.ts

@@ -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');

+ 1 - 1
packages/cli/src/utilities/vendure-plugin-ref.ts

@@ -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);
     }
 }