Browse Source

refactor(cli): Remove unused code, rework shared code location

Michael Bromley 1 year ago
parent
commit
f9e3d214f2
27 changed files with 65 additions and 654 deletions
  1. 4 3
      packages/cli/src/commands/add/codegen/add-codegen.ts
  2. 1 1
      packages/cli/src/commands/add/codegen/codegen-config-ref.ts
  3. 47 30
      packages/cli/src/commands/add/entity/add-entity.ts
  4. 1 1
      packages/cli/src/commands/add/entity/codemods/add-entity-to-plugin/add-entity-to-plugin.spec.ts
  5. 1 1
      packages/cli/src/commands/add/entity/codemods/add-entity-to-plugin/add-entity-to-plugin.ts
  6. 2 2
      packages/cli/src/commands/add/plugin/create-new-plugin.ts
  7. 3 3
      packages/cli/src/commands/add/ui-extensions/add-ui-extensions.ts
  8. 1 1
      packages/cli/src/commands/add/ui-extensions/codemods/add-ui-extension-static-prop/add-ui-extension-static-prop.spec.ts
  9. 1 1
      packages/cli/src/commands/add/ui-extensions/codemods/add-ui-extension-static-prop/add-ui-extension-static-prop.ts
  10. 1 1
      packages/cli/src/commands/add/ui-extensions/codemods/update-admin-ui-plugin-init/update-admin-ui-plugin-init.spec.ts
  11. 1 1
      packages/cli/src/commands/add/ui-extensions/codemods/update-admin-ui-plugin-init/update-admin-ui-plugin-init.ts
  12. 0 15
      packages/cli/src/commands/new/new.ts
  13. 0 143
      packages/cli/src/commands/new/plugin/new-plugin.ts
  14. 0 63
      packages/cli/src/commands/new/plugin/scaffold/api/admin.resolver.ts
  15. 0 80
      packages/cli/src/commands/new/plugin/scaffold/api/api-extensions.ts
  16. 0 54
      packages/cli/src/commands/new/plugin/scaffold/api/shop.resolver.ts
  17. 0 22
      packages/cli/src/commands/new/plugin/scaffold/constants.ts
  18. 0 54
      packages/cli/src/commands/new/plugin/scaffold/plugin.ts
  19. 0 79
      packages/cli/src/commands/new/plugin/scaffold/services/service.ts
  20. 0 12
      packages/cli/src/commands/new/plugin/scaffold/types.ts
  21. 0 23
      packages/cli/src/commands/new/plugin/types.ts
  22. 0 0
      packages/cli/src/shared/package-json-ref.ts
  23. 2 23
      packages/cli/src/shared/shared-prompts.ts
  24. 0 21
      packages/cli/src/shared/shared-scaffold/entity.ts
  25. 0 0
      packages/cli/src/shared/vendure-config-ref.ts
  26. 0 0
      packages/cli/src/shared/vendure-plugin-ref.ts
  27. 0 20
      packages/cli/src/utilities/scaffolder.ts

+ 4 - 3
packages/cli/src/commands/add/codegen/add-codegen.ts

@@ -2,11 +2,12 @@ import { log, note, outro, spinner } from '@clack/prompts';
 import path from 'path';
 import { StructureKind } from 'ts-morph';
 
+import { PackageJson } from '../../../shared/package-json-ref';
 import { analyzeProject, selectMultiplePluginClasses } from '../../../shared/shared-prompts';
+import { VendurePluginRef } from '../../../shared/vendure-plugin-ref';
 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';
+
+import { CodegenConfigRef } from './codegen-config-ref';
 
 export async function addCodegen(providedVendurePlugin?: VendurePluginRef) {
     const project = await analyzeProject({

+ 1 - 1
packages/cli/src/utilities/codegen-config-ref.ts → packages/cli/src/commands/add/codegen/codegen-config-ref.ts

@@ -10,7 +10,7 @@ import {
     SyntaxKind,
 } from 'ts-morph';
 
-import { createFile, getTsMorphProject } from './ast-utils';
+import { createFile, getTsMorphProject } from '../../../utilities/ast-utils';
 
 export class CodegenConfigRef {
     private readonly tempProject: Project;

+ 47 - 30
packages/cli/src/commands/add/entity/add-entity.ts

@@ -1,25 +1,23 @@
-import { cancel, isCancel, multiselect, outro } from '@clack/prompts';
-import { paramCase } from 'change-case';
+import { cancel, isCancel, multiselect, outro, text } from '@clack/prompts';
+import { paramCase, pascalCase } from 'change-case';
 import path from 'path';
-import { ClassDeclaration, StructureKind, SyntaxKind } from 'ts-morph';
+import { ClassDeclaration } from 'ts-morph';
 
-import { analyzeProject, getCustomEntityName, selectPlugin } from '../../../shared/shared-prompts';
+import { analyzeProject, selectPlugin } from '../../../shared/shared-prompts';
+import { VendurePluginRef } from '../../../shared/vendure-plugin-ref';
 import { createFile } from '../../../utilities/ast-utils';
-import { VendurePluginRef } from '../../../utilities/vendure-plugin-ref';
 
 import { addEntityToPlugin } from './codemods/add-entity-to-plugin/add-entity-to-plugin';
 
 const cancelledMessage = 'Add entity cancelled';
 
 export interface AddEntityTemplateContext {
-    entity: {
-        className: string;
-        fileName: string;
-        translationFileName: string;
-        features: {
-            customFields: boolean;
-            translatable: boolean;
-        };
+    className: string;
+    fileName: string;
+    translationFileName: string;
+    features: {
+        customFields: boolean;
+        translatable: boolean;
     };
 }
 
@@ -52,21 +50,19 @@ export async function addEntity(providedVendurePlugin?: VendurePluginRef) {
     }
 
     const context: AddEntityTemplateContext = {
-        entity: {
-            className: customEntityName,
-            fileName: paramCase(customEntityName) + '.entity',
-            translationFileName: paramCase(customEntityName) + '-translation.entity',
-            features: {
-                customFields: features.includes('customFields'),
-                translatable: features.includes('translatable'),
-            },
+        className: customEntityName,
+        fileName: paramCase(customEntityName) + '.entity',
+        translationFileName: paramCase(customEntityName) + '-translation.entity',
+        features: {
+            customFields: features.includes('customFields'),
+            translatable: features.includes('translatable'),
         },
     };
 
     const { entityClass, translationClass } = createEntity(vendurePlugin, context);
     addEntityToPlugin(vendurePlugin, entityClass);
     entityClass.getSourceFile().organizeImports();
-    if (context.entity.features.translatable) {
+    if (context.features.translatable) {
         addEntityToPlugin(vendurePlugin, translationClass);
         translationClass.getSourceFile().organizeImports();
     }
@@ -88,28 +84,28 @@ function createEntity(plugin: VendurePluginRef, context: AddEntityTemplateContex
         plugin.getSourceFile().getProject(),
         path.join(__dirname, 'templates/entity-translation.template.ts'),
     );
-    entityFile.move(path.join(entitiesDir, `${context.entity.fileName}.ts`));
-    translationFile.move(path.join(entitiesDir, `${context.entity.translationFileName}.ts`));
+    entityFile.move(path.join(entitiesDir, `${context.fileName}.ts`));
+    translationFile.move(path.join(entitiesDir, `${context.translationFileName}.ts`));
 
-    const entityClass = entityFile.getClass('ScaffoldEntity')?.rename(context.entity.className);
+    const entityClass = entityFile.getClass('ScaffoldEntity')?.rename(context.className);
     const customFieldsClass = entityFile
         .getClass('ScaffoldEntityCustomFields')
-        ?.rename(`${context.entity.className}CustomFields`);
+        ?.rename(`${context.className}CustomFields`);
     const translationClass = translationFile
         .getClass('ScaffoldTranslation')
-        ?.rename(`${context.entity.className}Translation`);
+        ?.rename(`${context.className}Translation`);
     const translationCustomFieldsClass = translationFile
         .getClass('ScaffoldEntityCustomFieldsTranslation')
-        ?.rename(`${context.entity.className}CustomFieldsTranslation`);
+        ?.rename(`${context.className}CustomFieldsTranslation`);
 
-    if (!context.entity.features.customFields) {
+    if (!context.features.customFields) {
         // Remove custom fields from entity
         customFieldsClass?.remove();
         translationCustomFieldsClass?.remove();
         removeCustomFieldsFromClass(entityClass);
         removeCustomFieldsFromClass(translationClass);
     }
-    if (!context.entity.features.translatable) {
+    if (!context.features.translatable) {
         // Remove translatable fields from entity
         translationClass?.remove();
         entityClass?.getProperty('localizedName')?.remove();
@@ -133,3 +129,24 @@ function removeImplementsFromClass(implementsName: string, entityClass?: ClassDe
         entityClass?.removeImplements(index);
     }
 }
+
+export async function getCustomEntityName(_cancelledMessage: string) {
+    const entityName = await text({
+        message: 'What is the name of the custom entity?',
+        initialValue: '',
+        validate: input => {
+            if (!input) {
+                return 'The custom entity name cannot be empty';
+            }
+            const pascalCaseRegex = /^[A-Z][a-zA-Z0-9]*$/;
+            if (!pascalCaseRegex.test(input)) {
+                return 'The custom entity name must be in PascalCase, e.g. "ProductReview"';
+            }
+        },
+    });
+    if (isCancel(entityName)) {
+        cancel(_cancelledMessage);
+        process.exit(0);
+    }
+    return pascalCase(entityName);
+}

+ 1 - 1
packages/cli/src/commands/add/entity/codemods/add-entity-to-plugin/add-entity-to-plugin.spec.ts

@@ -4,9 +4,9 @@ import { Project } from 'ts-morph';
 import { describe, expect, it } from 'vitest';
 
 import { defaultManipulationSettings } from '../../../../../constants';
+import { VendurePluginRef } from '../../../../../shared/vendure-plugin-ref';
 import { createFile, getPluginClasses } from '../../../../../utilities/ast-utils';
 import { expectSourceFileContentToMatch } from '../../../../../utilities/testing-utils';
-import { VendurePluginRef } from '../../../../../utilities/vendure-plugin-ref';
 
 import { addEntityToPlugin } from './add-entity-to-plugin';
 

+ 1 - 1
packages/cli/src/commands/add/entity/codemods/add-entity-to-plugin/add-entity-to-plugin.ts

@@ -1,7 +1,7 @@
 import { ClassDeclaration } from 'ts-morph';
 
+import { VendurePluginRef } from '../../../../../shared/vendure-plugin-ref';
 import { addImportsToFile } from '../../../../../utilities/ast-utils';
-import { VendurePluginRef } from '../../../../../utilities/vendure-plugin-ref';
 
 export function addEntityToPlugin(plugin: VendurePluginRef, entityClass: ClassDeclaration) {
     if (!entityClass) {

+ 2 - 2
packages/cli/src/commands/add/plugin/create-new-plugin.ts

@@ -3,9 +3,9 @@ import { constantCase, paramCase, pascalCase } from 'change-case';
 import * as fs from 'fs-extra';
 import path from 'path';
 
+import { VendureConfigRef } from '../../../shared/vendure-config-ref';
+import { VendurePluginRef } from '../../../shared/vendure-plugin-ref';
 import { addImportsToFile, createFile, getTsMorphProject } from '../../../utilities/ast-utils';
-import { VendureConfigRef } from '../../../utilities/vendure-config-ref';
-import { VendurePluginRef } from '../../../utilities/vendure-plugin-ref';
 import { addCodegen } from '../codegen/add-codegen';
 import { addEntity } from '../entity/add-entity';
 import { addUiExtensions } from '../ui-extensions/add-ui-extensions';

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

@@ -1,11 +1,11 @@
 import { log, note, outro, spinner } from '@clack/prompts';
 import path from 'path';
 
+import { PackageJson } from '../../../shared/package-json-ref';
 import { analyzeProject, selectPlugin } from '../../../shared/shared-prompts';
+import { VendureConfigRef } from '../../../shared/vendure-config-ref';
+import { VendurePluginRef } from '../../../shared/vendure-plugin-ref';
 import { createFile, getRelativeImportPath } from '../../../utilities/ast-utils';
-import { PackageJson } from '../../../utilities/package-utils';
-import { VendureConfigRef } from '../../../utilities/vendure-config-ref';
-import { VendurePluginRef } from '../../../utilities/vendure-plugin-ref';
 
 import { addUiExtensionStaticProp } from './codemods/add-ui-extension-static-prop/add-ui-extension-static-prop';
 import { updateAdminUiPluginInit } from './codemods/update-admin-ui-plugin-init/update-admin-ui-plugin-init';

+ 1 - 1
packages/cli/src/commands/add/ui-extensions/codemods/add-ui-extension-static-prop/add-ui-extension-static-prop.spec.ts

@@ -3,9 +3,9 @@ import { Project } from 'ts-morph';
 import { describe, expect, it } from 'vitest';
 
 import { defaultManipulationSettings } from '../../../../../constants';
+import { VendurePluginRef } from '../../../../../shared/vendure-plugin-ref';
 import { getPluginClasses } from '../../../../../utilities/ast-utils';
 import { expectSourceFileContentToMatch } from '../../../../../utilities/testing-utils';
-import { VendurePluginRef } from '../../../../../utilities/vendure-plugin-ref';
 
 import { addUiExtensionStaticProp } from './add-ui-extension-static-prop';
 

+ 1 - 1
packages/cli/src/commands/add/ui-extensions/codemods/add-ui-extension-static-prop/add-ui-extension-static-prop.ts

@@ -1,8 +1,8 @@
 import { ClassDeclaration } from 'ts-morph';
 
 import { AdminUiExtensionTypeName } from '../../../../../constants';
+import { VendurePluginRef } from '../../../../../shared/vendure-plugin-ref';
 import { addImportsToFile, kebabize } from '../../../../../utilities/ast-utils';
-import { VendurePluginRef } from '../../../../../utilities/vendure-plugin-ref';
 
 /**
  * @description

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

@@ -3,8 +3,8 @@ import { Project } from 'ts-morph';
 import { describe, it } from 'vitest';
 
 import { defaultManipulationSettings } from '../../../../../constants';
+import { VendureConfigRef } from '../../../../../shared/vendure-config-ref';
 import { expectSourceFileContentToMatch } from '../../../../../utilities/testing-utils';
-import { VendureConfigRef } from '../../../../../utilities/vendure-config-ref';
 
 import { updateAdminUiPluginInit } from './update-admin-ui-plugin-init';
 

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

@@ -1,8 +1,8 @@
 import { Node, ObjectLiteralExpression, StructureKind, SyntaxKind } from 'ts-morph';
 
 import { AdminUiAppConfigName } from '../../../../../constants';
+import { VendureConfigRef } from '../../../../../shared/vendure-config-ref';
 import { addImportsToFile } from '../../../../../utilities/ast-utils';
-import { VendureConfigRef } from '../../../../../utilities/vendure-config-ref';
 
 export function updateAdminUiPluginInit(
     vendureConfig: VendureConfigRef,

+ 0 - 15
packages/cli/src/commands/new/new.ts

@@ -1,15 +0,0 @@
-import { Argument, Command } from 'commander';
-
-import { newPlugin } from './plugin/new-plugin';
-
-export function registerNewCommand(program: Command) {
-    program
-        .command('new')
-        .addArgument(new Argument('<type>', 'type of scaffold').choices(['plugin']))
-        .description('Generate scaffold for your Vendure project')
-        .action(async (type: string) => {
-            if (type === 'plugin') {
-                await newPlugin();
-            }
-        });
-}

+ 0 - 143
packages/cli/src/commands/new/plugin/new-plugin.ts

@@ -1,143 +0,0 @@
-import { cancel, intro, isCancel, multiselect, outro, text } from '@clack/prompts';
-import { camelCase, constantCase, paramCase, pascalCase } from 'change-case';
-import * as fs from 'fs-extra';
-import path from 'path';
-
-import { getCustomEntityName } from '../../../shared/shared-prompts';
-import { renderEntity } from '../../../shared/shared-scaffold/entity';
-import { Scaffolder } from '../../../utilities/scaffolder';
-
-import { renderAdminResolver, renderAdminResolverWithEntity } from './scaffold/api/admin.resolver';
-import { renderApiExtensions } from './scaffold/api/api-extensions';
-import { renderShopResolver, renderShopResolverWithEntity } from './scaffold/api/shop.resolver';
-import { renderConstants } from './scaffold/constants';
-import { renderPlugin } from './scaffold/plugin';
-import { renderService, renderServiceWithEntity } from './scaffold/services/service';
-import { renderTypes } from './scaffold/types';
-import { GeneratePluginOptions, NewPluginTemplateContext } from './types';
-
-const cancelledMessage = 'Plugin setup cancelled.';
-
-export async function newPlugin() {
-    const options: GeneratePluginOptions = { name: '', customEntityName: '', pluginDir: '' } as any;
-    intro('Scaffolding a new Vendure plugin!');
-    if (!options.name) {
-        const name = await text({
-            message: 'What is the name of the plugin?',
-            initialValue: '',
-            validate: input => {
-                if (!/^[a-z][a-z-0-9]+$/.test(input)) {
-                    return 'The plugin name must be lowercase and contain only letters, numbers and dashes';
-                }
-            },
-        });
-
-        if (isCancel(name)) {
-            cancel(cancelledMessage);
-            process.exit(0);
-        } else {
-            options.name = name;
-        }
-    }
-    const features = await multiselect({
-        message: 'Which features would you like to include? (use ↑, ↓, space to select)',
-        options: [
-            { value: 'customEntity', label: 'Custom entity' },
-            { value: 'apiExtensions', label: 'GraphQL API extensions' },
-        ],
-        required: false,
-    });
-    if (Array.isArray(features)) {
-        options.withCustomEntity = features.includes('customEntity');
-        options.withApiExtensions = features.includes('apiExtensions');
-    }
-    if (options.withCustomEntity) {
-        options.customEntityName = await getCustomEntityName(cancelledMessage);
-    }
-    const pluginDir = getPluginDirName(options.name);
-    const confirmation = await text({
-        message: 'Plugin location',
-        initialValue: pluginDir,
-        placeholder: '',
-        validate: input => {
-            if (fs.existsSync(input)) {
-                return `A directory named "${input}" already exists. Please specify a different directory.`;
-            }
-        },
-    });
-
-    if (isCancel(confirmation)) {
-        cancel(cancelledMessage);
-        process.exit(0);
-    } else {
-        options.pluginDir = confirmation;
-        generatePlugin(options);
-    }
-}
-
-export function generatePlugin(options: GeneratePluginOptions) {
-    const nameWithoutPlugin = options.name.replace(/-?plugin$/i, '');
-    const normalizedName = nameWithoutPlugin + '-plugin';
-    const templateContext: NewPluginTemplateContext = {
-        ...options,
-        pluginName: pascalCase(normalizedName),
-        pluginInitOptionsName: constantCase(normalizedName) + '_OPTIONS',
-        service: {
-            className: pascalCase(nameWithoutPlugin) + 'Service',
-            instanceName: camelCase(nameWithoutPlugin) + 'Service',
-            fileName: paramCase(nameWithoutPlugin) + '.service',
-        },
-        entity: {
-            className: options.customEntityName,
-            instanceName: camelCase(options.customEntityName),
-            fileName: paramCase(options.customEntityName) + '.entity',
-        },
-    };
-
-    const scaffolder = new Scaffolder<NewPluginTemplateContext>();
-    scaffolder.addFile(renderPlugin, paramCase(nameWithoutPlugin) + '.plugin.ts');
-    scaffolder.addFile(renderTypes, 'types.ts');
-    scaffolder.addFile(renderConstants, 'constants.ts');
-
-    if (options.withApiExtensions) {
-        scaffolder.addFile(renderApiExtensions, 'api/api-extensions.ts');
-        if (options.withCustomEntity) {
-            scaffolder.addFile(renderShopResolverWithEntity, 'api/shop.resolver.ts');
-            scaffolder.addFile(renderAdminResolverWithEntity, 'api/admin.resolver.ts');
-        } else {
-            scaffolder.addFile(renderShopResolver, 'api/shop.resolver.ts');
-            scaffolder.addFile(renderAdminResolver, 'api/admin.resolver.ts');
-        }
-    }
-
-    if (options.withCustomEntity) {
-        scaffolder.addFile(renderEntity, `entities/${templateContext.entity.fileName}.ts`);
-        scaffolder.addFile(renderServiceWithEntity, `services/${templateContext.service.fileName}.ts`);
-    } else {
-        scaffolder.addFile(renderService, `services/${templateContext.service.fileName}.ts`);
-    }
-
-    const pluginDir = options.pluginDir;
-    scaffolder.createScaffold({
-        dir: pluginDir,
-        context: templateContext,
-    });
-
-    outro('✅ Plugin scaffolding complete!');
-}
-
-function getPluginDirName(name: string) {
-    const cwd = process.cwd();
-    const pathParts = cwd.split(path.sep);
-    const currentlyInPluginsDir = pathParts[pathParts.length - 1] === 'plugins';
-    const currentlyInRootDir = fs.pathExistsSync(path.join(cwd, 'package.json'));
-    const nameWithoutPlugin = name.replace(/-?plugin$/i, '');
-
-    if (currentlyInPluginsDir) {
-        return path.join(cwd, paramCase(nameWithoutPlugin));
-    }
-    if (currentlyInRootDir) {
-        return path.join(cwd, 'src', 'plugins', paramCase(nameWithoutPlugin));
-    }
-    return path.join(cwd, paramCase(nameWithoutPlugin));
-}

+ 0 - 63
packages/cli/src/commands/new/plugin/scaffold/api/admin.resolver.ts

@@ -1,63 +0,0 @@
-import { NewPluginTemplateContext } from '../../types';
-
-export function renderAdminResolverWithEntity(context: NewPluginTemplateContext) {
-    return /* language=TypeScript */ `
-import { Args, Resolver, Mutation } from '@nestjs/graphql';
-import { Allow, Ctx, RequestContext, Transaction, Permission } from '@vendure/core';
-
-import { ${context.entity.instanceName}Permission } from '../constants';
-import { ${context.service.className} } from '../services/${context.service.fileName}';
-import { ${context.entity.className} } from '../entities/${context.entity.fileName}';
-
-// TODO: Set up graphql-code-generator to generate the types for the following inputs
-type Create${context.customEntityName}Input = any;
-type Update${context.customEntityName}Input = any;
-
-@Resolver()
-export class AdminResolver {
-    constructor(private ${context.service.instanceName}: ${context.service.className}) {
-    }
-
-    @Transaction()
-    @Mutation()
-    @Allow(${context.entity.instanceName}Permission.Create)
-    create${context.entity.className}(@Ctx() ctx: RequestContext, @Args() args: { input: Create${context.customEntityName}Input }): Promise<${context.entity.className}> {
-        return this.${context.service.instanceName}.create(ctx, args.input);
-    }
-
-    @Transaction()
-    @Mutation()
-    @Allow(${context.entity.instanceName}Permission.Update)
-    update${context.entity.className}(
-        @Ctx() ctx: RequestContext,
-        @Args() args: { input: Update${context.customEntityName}Input },
-    ): Promise<${context.entity.className} | undefined> {
-        return this.${context.service.instanceName}.update(ctx, args.input);
-    }
-}`;
-}
-
-export function renderAdminResolver(context: NewPluginTemplateContext) {
-    return /* language=TypeScript */ `
-import { Args, Query, Mutation, Resolver } from '@nestjs/graphql';
-import { Ctx, PaginatedList, RequestContext, Transaction } from '@vendure/core';
-
-import { ${context.service.className} } from '../services/${context.service.fileName}';
-
-@Resolver()
-export class AdminResolver {
-    constructor(private ${context.service.instanceName}: ${context.service.className}) {
-    }
-
-    @Query()
-    exampleShopQuery(@Ctx() ctx: RequestContext) {
-        return this.${context.service.instanceName}.exampleMethod(ctx);
-    }
-
-    @Mutation()
-    @Transaction()
-    exampleShopMutation(@Ctx() ctx: RequestContext, @Args() args: { input: string }) {
-        return this.${context.service.instanceName}.exampleMethod(ctx, args);
-    }
-}`;
-}

+ 0 - 80
packages/cli/src/commands/new/plugin/scaffold/api/api-extensions.ts

@@ -1,80 +0,0 @@
-import { constantCase, pascalCase } from 'change-case';
-
-import { NewPluginTemplateContext } from '../../types';
-
-export function renderApiExtensions(context: NewPluginTemplateContext) {
-    if (!context.withApiExtensions) {
-        return '';
-    }
-    if (!context.withCustomEntity) {
-        return /* language=TypeScript */ `
-import gql from 'graphql-tag';
-export const shopApiExtensions = gql\`
-    extend type Query {
-       exampleShopQuery: String!
-    }
-    extend type Mutation {
-       exampleShopMutation(input: String!): String!
-    }
-\`;
-
-export const adminApiExtensions = gql\`
-     extend type Query {
-       exampleAdminQuery: String!
-    }
-    extend type Mutation {
-       exampleAdminMutation(input: String!): String!
-    }
-\`;
-`;
-    } else {
-        const entityName = context.entity.className;
-        return /* language=TypeScript */ `
-import gql from 'graphql-tag';
-
-export const commonApiExtensions = gql\`
-    type ${entityName} implements Node {
-        id: ID!
-        createdAt: DateTime!
-        updatedAt: DateTime!
-        name: String!
-    }
-
-    type ${entityName}List implements PaginatedList {
-        items: [${entityName}!]!
-        totalItems: Int!
-    }
-
-    extend type Query {
-        ${context.entity.instanceName}s(options: ${entityName}ListOptions): ${entityName}List!
-        ${context.entity.instanceName}(id: ID!): ${entityName}
-    }
-
-    # Auto-generated at runtime
-    input ${entityName}ListOptions
-\`;
-
-export const shopApiExtensions = gql\`
-    \${commonApiExtensions}
-\`;
-
-export const adminApiExtensions = gql\`
-    \${commonApiExtensions}
-
-    extend type Mutation {
-        create${entityName}(input: Create${entityName}Input!): ${entityName}!
-        update${entityName}(input: Update${entityName}Input!): ${entityName}!
-    }
-
-    input Create${entityName}Input {
-        name: String!
-    }
-
-    input Update${entityName}Input {
-        id: ID!
-        name: String!
-    }
-\`;
-`;
-    }
-}

+ 0 - 54
packages/cli/src/commands/new/plugin/scaffold/api/shop.resolver.ts

@@ -1,54 +0,0 @@
-import { NewPluginTemplateContext } from '../../types';
-
-export function renderShopResolverWithEntity(context: NewPluginTemplateContext) {
-    return /* language=TypeScript */ `
-import { Args, Query, Resolver } from '@nestjs/graphql';
-import { Ctx, PaginatedList, RequestContext, ListQueryOptions } from '@vendure/core';
-
-import { ${context.service.className} } from '../services/${context.service.fileName}';
-import { ${context.entity.className} } from '../entities/${context.entity.fileName}';
-
-@Resolver()
-export class ShopResolver {
-    constructor(private ${context.service.instanceName}: ${context.service.className}) {
-    }
-
-    @Query()
-    ${context.entity.instanceName}s(
-        @Ctx() ctx: RequestContext,
-        @Args() args: { options: ListQueryOptions<${context.customEntityName}> },
-    ): Promise<PaginatedList<${context.customEntityName}>> {
-        return this.${context.service.instanceName}.findAll(ctx, args.options || undefined);
-    }
-
-    @Query()
-    ${context.entity.instanceName}(@Ctx() ctx: RequestContext, @Args() args: { id: string }): Promise<${context.customEntityName} | null> {
-        return this.${context.service.instanceName}.findOne(ctx, args.id);
-    }
-}`;
-}
-
-export function renderShopResolver(context: NewPluginTemplateContext) {
-    return /* language=TypeScript */ `
-import { Args, Query, Mutation, Resolver } from '@nestjs/graphql';
-import { Ctx, PaginatedList, RequestContext, Transaction } from '@vendure/core';
-
-import { ${context.service.className} } from '../services/${context.service.fileName}';
-
-@Resolver()
-export class ShopResolver {
-    constructor(private ${context.service.instanceName}: ${context.service.className}) {
-    }
-
-    @Query()
-    exampleShopQuery(@Ctx() ctx: RequestContext) {
-        return this.${context.service.instanceName}.exampleMethod(ctx);
-    }
-
-    @Mutation()
-    @Transaction()
-    exampleShopMutation(@Ctx() ctx: RequestContext, @Args() args: { input: string }) {
-        return this.${context.service.instanceName}.exampleMethod(ctx, args);
-    }
-}`;
-}

+ 0 - 22
packages/cli/src/commands/new/plugin/scaffold/constants.ts

@@ -1,22 +0,0 @@
-import { constantCase, pascalCase } from 'change-case';
-
-import { NewPluginTemplateContext } from '../types';
-
-export function renderConstants(context: NewPluginTemplateContext): string {
-    const { pluginName, pluginInitOptionsName } = context;
-    const optionalImports: string[] = [];
-    const optionalStatements: string[] = [];
-    if (context.withCustomEntity) {
-        optionalImports.push(`import { CrudPermissionDefinition } from '@vendure/core';`);
-        optionalStatements.push(
-            `export const ${context.entity.instanceName}Permission = new CrudPermissionDefinition('${context.entity.className}');`,
-        );
-    }
-    return /* language=TypeScript */ `
-${optionalImports.join('\n')}
-
-export const ${pluginInitOptionsName} = Symbol('${pluginInitOptionsName}');
-export const loggerCtx = '${pluginName}';
-${optionalStatements.join('\n')}
-`;
-}

+ 0 - 54
packages/cli/src/commands/new/plugin/scaffold/plugin.ts

@@ -1,54 +0,0 @@
-import { constantCase, pascalCase } from 'change-case';
-
-import { NewPluginTemplateContext } from '../types';
-
-export function renderPlugin(context: NewPluginTemplateContext) {
-    const { pluginName, pluginInitOptionsName } = context;
-    const optionalImports: string[] = [];
-    const optionalMetadata: string[] = [];
-    if (context.withCustomEntity) {
-        optionalImports.push(
-            `import { ${context.entity.className} } from './entities/${context.entity.fileName}';`,
-        );
-        optionalMetadata.push(`entities: [${context.entity.className}],`);
-    } else {
-        optionalMetadata.push(`entities: [],`);
-    }
-    if (context.withApiExtensions) {
-        optionalImports.push(`import { shopApiExtensions, adminApiExtensions } from './api/api-extensions';`);
-        optionalImports.push(`import { ShopResolver } from './api/shop.resolver';`);
-        optionalImports.push(`import { AdminResolver } from './api/admin.resolver';`);
-        optionalMetadata.push(`shopApiExtensions: { resolvers: [ShopResolver], schema: shopApiExtensions },`);
-        optionalMetadata.push(
-            `adminApiExtensions: { resolvers: [AdminResolver], schema: adminApiExtensions },`,
-        );
-    }
-
-    return /* language=TypeScript */ `
-import { PluginCommonModule, Type, VendurePlugin } from '@vendure/core';
-import path from 'path';
-
-import { ${context.service.className} } from './services/${context.service.fileName}';
-import { ${pluginInitOptionsName} } from './constants';
-import { PluginInitOptions } from './types';
-${optionalImports.join('\n')}
-
-@VendurePlugin({
-    imports: [PluginCommonModule],
-    ${optionalMetadata.join('\n    ')}
-    providers: [
-        ${context.service.className},
-        { provide: ${pluginInitOptionsName}, useFactory: () => ${pluginName}.options },
-    ],
-    compatibility: '^2.0.0',
-})
-export class ${pluginName} {
-    static options: PluginInitOptions;
-
-    static init(options: PluginInitOptions): Type<${pluginName}> {
-        this.options = options;
-        return ${pluginName};
-    }
-}
-`;
-}

+ 0 - 79
packages/cli/src/commands/new/plugin/scaffold/services/service.ts

@@ -1,79 +0,0 @@
-import { paramCase } from 'change-case';
-
-import { NewPluginTemplateContext } from '../../types';
-
-export function renderService(context: NewPluginTemplateContext) {
-    return /* language=TypeScript */ `
-import { Inject, Injectable } from '@nestjs/common';
-import { RequestContext, TransactionalConnection, patchEntity } from '@vendure/core';
-
-import { ${context.pluginInitOptionsName} } from '../constants';
-import { PluginInitOptions } from '../types';
-
-@Injectable()
-export class ${context.service.className} {
-    constructor(
-        private connection: TransactionalConnection,
-        @Inject(${context.pluginInitOptionsName}) private options: PluginInitOptions,
-    ) {}
-
-    async exampleMethod(
-        ctx: RequestContext,
-        options?: { input?: string },
-    ): Promise<string> {
-        return options?.input ? 'Hello \${options.input}' : 'Hello World';
-    }
-}
-`;
-}
-
-export function renderServiceWithEntity(context: NewPluginTemplateContext) {
-    return /* language=TypeScript */ `
-import { Inject, Injectable } from '@nestjs/common';
-import { ListQueryBuilder, ListQueryOptions, PaginatedList, RequestContext, TransactionalConnection } from '@vendure/core';
-
-import { ${context.customEntityName} } from '../entities/${context.entity.fileName}';
-import { ${context.pluginInitOptionsName} } from '../constants';
-import { PluginInitOptions } from '../types';
-
-// TODO: Set up graphql-code-generator to generate the types for the following inputs
-type Create${context.customEntityName}Input = any;
-type Update${context.customEntityName}Input = any;
-
-@Injectable()
-export class ${context.service.className} {
-    constructor(
-        private connection: TransactionalConnection,
-        @Inject(${context.pluginInitOptionsName}) private options: PluginInitOptions,
-        private listQueryBuilder: ListQueryBuilder,
-    ) {}
-
-    async findAll(
-        ctx: RequestContext,
-        options?: ListQueryOptions<${context.customEntityName}>,
-    ): Promise<PaginatedList<${context.customEntityName}>> {
-        return this.listQueryBuilder
-            .build(${context.customEntityName}, options, { ctx })
-            .getManyAndCount()
-            .then(([items, totalItems]) => ({
-                items,
-                totalItems,
-            }));
-    }
-
-    async findOne(ctx: RequestContext, id: string): Promise<${context.customEntityName} | null> {
-        return this.connection.getRepository(ctx, ${context.customEntityName}).findOne({ where: { id } });
-    }
-
-    async create(ctx: RequestContext, input: Create${context.customEntityName}Input): Promise<${context.customEntityName}> {
-        return this.connection.getRepository(ctx, ${context.customEntityName}).save(new ${context.customEntityName}(input));
-    }
-
-    async update(ctx: RequestContext, input: Update${context.customEntityName}Input): Promise<${context.customEntityName}> {
-        const example = await this.connection.getEntityOrThrow(ctx, ${context.customEntityName}, input.id);
-        const updated = patchEntity(example, input);
-        return this.connection.getRepository(ctx, ${context.customEntityName}).save(updated);
-    }
-}
-`;
-}

+ 0 - 12
packages/cli/src/commands/new/plugin/scaffold/types.ts

@@ -1,12 +0,0 @@
-import { NewPluginTemplateContext } from '../types';
-
-export function renderTypes(options: NewPluginTemplateContext): string {
-    return /* language=TypeScript */ `
-/**
- * The plugin can be configured using the following options:
- */
-export interface PluginInitOptions {
-    exampleOption: string;
-}
-`;
-}

+ 0 - 23
packages/cli/src/commands/new/plugin/types.ts

@@ -1,23 +0,0 @@
-export interface GeneratePluginOptions {
-    name: string;
-    withCustomEntity: boolean;
-    withApiExtensions: boolean;
-    withAdminUi: boolean;
-    customEntityName: string;
-    pluginDir: string;
-}
-
-export type NewPluginTemplateContext = GeneratePluginOptions & {
-    pluginName: string;
-    pluginInitOptionsName: string;
-    service: {
-        instanceName: string;
-        className: string;
-        fileName: string;
-    };
-    entity: {
-        instanceName: string;
-        className: string;
-        fileName: string;
-    };
-};

+ 0 - 0
packages/cli/src/utilities/package-utils.ts → packages/cli/src/shared/package-json-ref.ts


+ 2 - 23
packages/cli/src/shared/shared-prompts.ts

@@ -1,31 +1,10 @@
-import { cancel, isCancel, multiselect, select, spinner, text } from '@clack/prompts';
-import { pascalCase } from 'change-case';
+import { cancel, isCancel, multiselect, select, spinner } from '@clack/prompts';
 import { ClassDeclaration, Project } from 'ts-morph';
 
 import { Messages } from '../constants';
 import { getPluginClasses, getTsMorphProject } from '../utilities/ast-utils';
-import { VendurePluginRef } from '../utilities/vendure-plugin-ref';
 
-export async function getCustomEntityName(cancelledMessage: string) {
-    const entityName = await text({
-        message: 'What is the name of the custom entity?',
-        initialValue: '',
-        validate: input => {
-            if (!input) {
-                return 'The custom entity name cannot be empty';
-            }
-            const pascalCaseRegex = /^[A-Z][a-zA-Z0-9]*$/;
-            if (!pascalCaseRegex.test(input)) {
-                return 'The custom entity name must be in PascalCase, e.g. "ProductReview"';
-            }
-        },
-    });
-    if (isCancel(entityName)) {
-        cancel(cancelledMessage);
-        process.exit(0);
-    }
-    return pascalCase(entityName);
-}
+import { VendurePluginRef } from './vendure-plugin-ref';
 
 export async function analyzeProject(options: {
     providedVendurePlugin?: VendurePluginRef;

+ 0 - 21
packages/cli/src/shared/shared-scaffold/entity.ts

@@ -1,21 +0,0 @@
-export function renderEntity<T extends { entity: { className: string } }>(context: T): string {
-    return /* language=TypeScript */ `
-import { Entity, Column } from 'typeorm';
-import { VendureEntity, DeepPartial, HasCustomFields } from '@vendure/core';
-
-export class ${context.entity.className}CustomFields {}
-
-@Entity()
-export class ${context.entity.className} extends VendureEntity implements HasCustomFields {
-    constructor(input?: DeepPartial<${context.entity.className}>) {
-        super(input);
-    }
-
-    @Column()
-    name: string;
-    
-    @Column(type => ${context.entity.className}CustomFields)
-    customFields: ${context.entity.className}CustomFields;
-}
-`;
-}

+ 0 - 0
packages/cli/src/utilities/vendure-config-ref.ts → packages/cli/src/shared/vendure-config-ref.ts


+ 0 - 0
packages/cli/src/utilities/vendure-plugin-ref.ts → packages/cli/src/shared/vendure-plugin-ref.ts


+ 0 - 20
packages/cli/src/utilities/scaffolder.ts

@@ -1,20 +0,0 @@
-import * as fs from 'fs-extra';
-import path from 'path';
-
-export class Scaffolder<TemplateContext = Record<string, any>> {
-    private files: Array<{ render: (context: TemplateContext) => string; path: string }> = [];
-
-    addFile(render: (context: TemplateContext) => string, filePath: string) {
-        this.files.push({ render, path: filePath });
-    }
-
-    createScaffold(options: { dir: string; context: TemplateContext }) {
-        fs.ensureDirSync(options.dir);
-        this.files.forEach(file => {
-            const filePath = path.join(options.dir, file.path);
-            const rendered = file.render(options.context).trim();
-            fs.ensureFileSync(filePath);
-            fs.writeFileSync(filePath, rendered);
-        });
-    }
-}