Skip to content

Commit

Permalink
feat: streamline creating custom templates
Browse files Browse the repository at this point in the history
  • Loading branch information
k-capehart committed May 30, 2024
1 parent c06d540 commit 2608ec9
Show file tree
Hide file tree
Showing 10 changed files with 256 additions and 151 deletions.
50 changes: 40 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,50 @@ The `--template` flag is used to choose which template to generate the apex code
- An extendable Apex Trigger Handler virtual class: https://github.com/k-capehart/sfdc-trigger-framework
- A Custom Setting called BypassAutomation\_\_c
- A checkbox field on BypassAutomation for the given Salesforce object
- An Apex trigger
- An Apex handler class that extends the virtual class, and uses the BypassAutomation\_\_c object to determine if logic should be skipped
- An Apex trigger that calls a handler class
- An Apex handler class that extends the virtual class and uses the BypassAutomation\_\_c object to determine if logic should be skipped
- An Apex helper class
- An Apex test class for the helper class

If you want to override a given template, then use the `--template-override` flag. The value given to the flag should be the path to a directory containing identically named files for a given template.
For example, to override template 1:
If you want to create a custom template, then use the `--custom-template` flag. The value given to the flag should be the path to a directory containing templates for classes, triggers, objects, and/or fields. The directory should contain a `init.json` and `sobject.json` that provide instructions on which files to use, what their final name should be, and what type of file they are. `init.json` is used with the `--init` flag. `sobject.json` is used with the `--sobject` flag.

For example, imagine the following JSON file is stored at the relative path of `templates/sobject.json`. It is assumed that within this directory are also 5 other files called `BypassCustomField.txt`, `SObjectTrigger.txt`, `SObjectTriggerHandler.txt`, `SObjectTriggerHelper.txt`, and `SObjectTriggerHelper_Test.txt`. The `{{sobject}}` token is replaced with the value given in the `--sobject` flag.

```json
{
"BypassCustomField.txt": {
"type": "field",
"name": "{{sobject}}__c",
"object": "BypassAutomation__c"
},
"SObjectTrigger.txt": {
"type": "trigger",
"name": "{{sobject}}Trigger"
},
"SObjectTriggerHandler.txt": {
"type": "class",
"name": "{{sobject}}TriggerHandler"
},
"SObjectTriggerHelper.txt": {
"type": "class",
"name": "{{sobject}}Helper"
},
"SObjectTriggerHelper_Test.txt": {
"type": "class",
"name": "{{sobject}}Helper_Test"
}
}
```

Running the command: `sf kc trigger-framework --custom-template templates/ --sobject Account` will create a 5 files:

- Account\_\_c.field-meta.xml
- AccountTrigger.trigger
- AccountTriggerHandler.cls
- AccountTriggerHelper.cls
- AccountTriggerHelper_Test.cls

1. Copy and paste the contents of this folder into a local directory, such as `templates/`: https://github.com/k-capehart/kc-sf-plugin/tree/main/src/templates/template-1
2. Modify the content of the text files according to your specific needs
- Note that `{{sobject}}` is a token that will be replaced with the given Salesforce Object name given in the `--sobject` flag
3. Run the commands:
<br/>`$ sf kc trigger-framework --template 1 --template-override templates/ --init`
<br/>`$ sf kc trigger-framework --template 1 --template-override templates/ --sobject Account`
For more template examples: https://github.com/k-capehart/kc-sf-plugin/tree/main/src/templates/

## Commands

Expand Down
10 changes: 5 additions & 5 deletions messages/kc.trigger-framework.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,15 @@ Use the `--init` flag to initialize the framework, then the `--sobject` flag to

Initialize a trigger framework using template-1.

<%= config.bin %> <%= command.id %> --template 1 --template-override templates/ --init
<%= config.bin %> <%= command.id %> --template 1 --init

Create a new trigger and related components for the Account and Contact object using template-1.

<%= config.bin %> <%= command.id %> --template 1 --sobject Account --sobject Contact

Create a new trigger and related components by overriding template-1 using files located at templates/.
Create a new trigger and related components with a custom template by providing the path to the locally stored templates.

<%= config.bin %> <%= command.id %> --template 1 --template-override templates/ --sobject Account
<%= config.bin %> <%= command.id %> --custom-template templates/ --sobject Account

# flags.target-dir.summary

Expand All @@ -34,9 +34,9 @@ The name of the SObject that the trigger and classes will be created for.

The template that should be used to generate the trigger framework.

# flags.template-override.summary
# flags.custom-template.summary

The directory in which the custom templates are located.
The directory in which the custom templates are located. View docs for more information on creating templates: https://github.com/k-capehart/kc-sf-plugin

# flags.init.summary

Expand Down
40 changes: 20 additions & 20 deletions src/commands/kc/trigger-framework.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ import * as path from 'node:path';
import { fileURLToPath } from 'node:url';
import { SfCommand, Flags } from '@salesforce/sf-plugins-core';
import { Messages } from '@salesforce/core';
import { generateTemplate1, initializeTemplate1 } from '../../utils/triggerFactory.js';
import { generateTemplates } from '../../utils/triggerFactory.js';

Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
const messages = Messages.loadMessages('kc-sf-plugin', 'kc.trigger-framework');

export type KcApexFactoryTriggerFrameworkResult = {
export type KcTriggerFrameworkResult = {
createdFiles: string[];
};

export default class KcApexFactoryTriggerFramework extends SfCommand<KcApexFactoryTriggerFrameworkResult> {
export default class KcTriggerFramework extends SfCommand<KcTriggerFrameworkResult> {
public static readonly summary = messages.getMessage('summary');
public static readonly description = messages.getMessage('description');
public static readonly examples = messages.getMessages('examples');
Expand All @@ -26,51 +26,51 @@ export default class KcApexFactoryTriggerFramework extends SfCommand<KcApexFacto
init: Flags.boolean({
summary: messages.getMessage('flags.init.summary'),
char: 'i',
exactlyOne: ['sobject', 'init'],
exactlyOne: ['init', 'sobject'],
}),
sobject: Flags.string({
summary: messages.getMessage('flags.sobject.summary'),
char: 's',
multiple: true,
exactlyOne: ['sobject', 'init'],
exactlyOne: ['init', 'sobject'],
}),
template: Flags.option({
summary: messages.getMessage('flags.template.summary'),
char: 't',
required: true,
options: ['1'] as const,
default: '1',
exactlyOne: ['template', 'custom-template'],
})(),
'template-override': Flags.directory({
summary: messages.getMessage('flags.template-override.summary'),
'custom-template': Flags.directory({
summary: messages.getMessage('flags.custom-template.summary'),
exists: true,
exactlyOne: ['template', 'custom-template'],
}),
};

public async run(): Promise<KcApexFactoryTriggerFrameworkResult> {
const { flags } = await this.parse(KcApexFactoryTriggerFramework);
public async run(): Promise<KcTriggerFrameworkResult> {
const { flags } = await this.parse(KcTriggerFramework);
const targetDir = flags['target-dir'];
const init = flags['init'];
const sobjects = flags['sobject'];
const template = flags['template'];
let templateDir = flags['template-override'];
let createdFiles: string[] = [];

const customTemplateDir = flags['custom-template'];
const defaultTemplateDir = '../../templates/';
const filename = fileURLToPath(import.meta.url);
const dirname = path.dirname(filename);
let templateDir: string;

switch (template) {
case '1':
if (templateDir === undefined) {
templateDir = path.resolve(dirname, defaultTemplateDir.concat('template-1/'));
}
if (init) {
createdFiles = initializeTemplate1(targetDir, templateDir);
} else if (sobjects !== undefined) {
createdFiles = generateTemplate1(sobjects, targetDir, templateDir);
case undefined:
if (customTemplateDir !== undefined) {
createdFiles = generateTemplates(targetDir, customTemplateDir, init, sobjects);
}
break;
case '1':
templateDir = path.resolve(dirname, defaultTemplateDir.concat('template-1/'));
createdFiles = generateTemplates(targetDir, templateDir, init, sobjects);
break;

default:
break;
Expand Down
15 changes: 15 additions & 0 deletions src/templates/template-1/init.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"BypassCustomObject.txt": {
"type": "object",
"name": "BypassAutomation__c",
"init": true
},
"TriggerHandlerVirtualClass.txt": {
"type": "class",
"name": "TriggerHandler"
},
"TriggerHandlerVirtualClass_Test.txt": {
"type": "class",
"name": "TriggerHandler_Test"
}
}
23 changes: 23 additions & 0 deletions src/templates/template-1/sobject.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"BypassCustomField.txt": {
"type": "field",
"name": "{{sobject}}__c",
"object": "BypassAutomation__c"
},
"SObjectTrigger.txt": {
"type": "trigger",
"name": "{{sobject}}Trigger"
},
"SObjectTriggerHandler.txt": {
"type": "class",
"name": "{{sobject}}TriggerHandler"
},
"SObjectTriggerHelper.txt": {
"type": "class",
"name": "{{sobject}}Helper"
},
"SObjectTriggerHelper_Test.txt": {
"type": "class",
"name": "{{sobject}}Helper_Test"
}
}
Loading

0 comments on commit 2608ec9

Please sign in to comment.