Skip to content

Commit

Permalink
feat: support aura/lwc component templates
Browse files Browse the repository at this point in the history
@W-9191596@
  • Loading branch information
smithgp committed May 24, 2021
1 parent 5a9eeca commit 0648ff5
Show file tree
Hide file tree
Showing 20 changed files with 295 additions and 73 deletions.
1 change: 1 addition & 0 deletions packages/plugin-templates/messages/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
"MissingAuraFolder": "Lightning bundles must have a parent folder named 'aura'.",
"MissingAppname": "Missing required flag:\n -n, --appname APPNAME name of the generated Lightning app\nSee more help with --help\n",
"MissingComponentName": "Missing required flag:\n -n, --componentname COMPONENTNAME name of the generated Lightning component\nSee more help with --help\n",
"MissingLightningComponentTemplate": "Template %s not available for component type %s.",
"MissingLWCFolder": "Lightning bundles must have a parent folder named 'lwc'.",
"MissingEventname": "Missing required flag:\n -n, --eventname EVENTNAME name of the generated Lightning event\nSee more help with --help\n",
"MissingInterfacename": "Missing required flag:\n -n, --interfacename INTERFACENAME name of the generated Lightning interface\nSee more help with --help\n",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { AnyJson } from '@salesforce/ts-types';
import { MessageUtil, TemplateCommand } from '../../../../utils';

const lightningComponentFileSuffix = /.cmp$/;
const lightningWebComponentFileSuffix = /.js$/;
const BUNDLE_TYPE = MessageUtil.get('Component');

export default class LightningComponent extends TemplateCommand {
Expand Down Expand Up @@ -53,10 +54,18 @@ export default class LightningComponent extends TemplateCommand {
char: 't',
description: MessageUtil.get('TemplateFlagDescription'),
longDescription: MessageUtil.get('TemplateFlagLongDescription'),
default: 'DefaultLightningCmp',
options: CreateUtil.getCommandTemplatesForFiletype(
lightningComponentFileSuffix,
'lightningcomponent'
default: 'default',
options: Array.from(
new Set([
...CreateUtil.getCommandTemplatesInSubdirs('lightningcomponent', {
subdir: 'aura',
filetype: lightningComponentFileSuffix
}),
...CreateUtil.getCommandTemplatesInSubdirs('lightningcomponent', {
subdir: 'lwc',
filetype: lightningWebComponentFileSuffix
})
]).values()
)
}),
outputdir: flags.string({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,31 @@ describe('Lightning component creation tests:', () => {
);
}
);

test
.withOrg()
.withProject()
.stdout()
.command([
'force:lightning:component:create',
'--componentname',
'foo',
'--outputdir',
'aura',
'--template',
'default'
])
.it(
'should create lightning aura component files from default template in the aura output directory',
ctx => {
assert.file(AuraLightningTestFormatter.fileformatter('foo', 'foo'));
assert.file(path.join('aura', 'foo', 'foo.cmp-meta.xml'));
assert.fileContent(
path.join('aura', 'foo', 'foo.cmp-meta.xml'),
'<AuraDefinitionBundle xmlns="http://soap.sforce.com/2006/04/metadata">'
);
}
);
});

describe('Check lightning aura components creation without -meta.xml file', () => {
Expand Down Expand Up @@ -112,12 +137,12 @@ describe('Lightning component creation tests:', () => {
.it(
'should create lightning web component files in the lwc output directory with the internal flag for disabling -meta.xml files',
ctx => {
assert.file(
path.join('lwc', 'internallwctest', 'internallwctest.html')
);
assert.noFile(
path.join('lwc', 'internallwctest', 'internallwctest.js-meta.xml')
);
assert.file(
path.join('lwc', 'internallwctest', 'internallwctest.html')
);
assert.file(
path.join('lwc', 'internallwctest', 'internallwctest.js')
);
Expand All @@ -144,9 +169,43 @@ describe('Lightning component creation tests:', () => {
'lwc'
])
.it(
'should create lightning web component files in the lwc output directory with the internal flag for disabling -meta.xml files',
'should create lightning web component files in the lwc output directory',
ctx => {
assert.file(path.join('lwc', 'foo', 'foo.js-meta.xml'));
assert.file(path.join('lwc', 'foo', 'foo.html'));
assert.file(path.join('lwc', 'foo', 'foo.js'));
assert.fileContent(
path.join('lwc', 'foo', 'foo.js'),
'export default class Foo extends LightningElement {}'
);
}
);

test
.withOrg()
.withProject()
.stdout()
.command([
'force:lightning:component:create',
'--componentname',
'foo',
'--outputdir',
'lwc',
'--type',
'lwc',
'--template',
'default'
])
.it(
'should create lightning web component files from default template in the lwc output directory',
ctx => {
assert.file(path.join('lwc', 'foo', 'foo.js-meta.xml'));
assert.file(path.join('lwc', 'foo', 'foo.html'));
assert.file(path.join('lwc', 'foo', 'foo.js'));
assert.fileContent(
path.join('lwc', 'foo', 'foo.js'),
'export default class Foo extends LightningElement {}'
);
}
);
});
Expand Down Expand Up @@ -184,5 +243,23 @@ describe('Lightning component creation tests:', () => {
.it('should throw missing lwc parent folder error', ctx => {
expect(ctx.stderr).to.contain(messages.getMessage('MissingLWCFolder'));
});
test
.withOrg()
.withProject()
.stderr()
.command([
'force:lightning:component:create',
'--outputdir',
'lwc',
'--componentname',
'foo',
'--type',
'lwc',
'--template',
'foo'
])
.it('should throw invalid template error', ctx => {
expect(ctx.stderr).to.contain(messages.getMessage('InvalidTemplate'));
});
});
});
146 changes: 86 additions & 60 deletions packages/templates/src/generators/lightningComponentGenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,19 @@ export default class LightningComponentGenerator extends SfdxGenerator<
throw new Error(nls.localize('MissingAuraDir'));
}
}

if (
CreateUtil.getCommandTemplatesInSubdirs('lightningcomponent', {
subdir: this.options.type
}).indexOf(this.options.template) < 0
) {
throw new Error(
nls.localize('MissingLightningComponentTemplate', [
this.options.template,
this.options.type
])
);
}
}

public writing() {
Expand All @@ -41,14 +54,21 @@ export default class LightningComponentGenerator extends SfdxGenerator<
type,
internal
} = this.options;
// tslint:disable-next-line:no-unused-expression

if (type === 'aura') {
this.sourceRoot(
path.join(__dirname, '..', 'templates', 'lightningcomponent', 'aura')
path.join(
__dirname,
'..',
'templates',
'lightningcomponent',
'aura',
template
)
);
if (!internal) {
this.fs.copyTpl(
this.templatePath('_auradefinitionbundle.cmp-meta.xml'),
this.templatePath(`${template}.cmp-meta.xml`),
this.destinationPath(
path.join(outputdir, componentname, `${componentname}.cmp-meta.xml`)
),
Expand All @@ -60,63 +80,62 @@ export default class LightningComponentGenerator extends SfdxGenerator<
);
}
this.fs.copyTpl(
this.templatePath('DefaultLightningAuradoc.auradoc'),
this.templatePath(`${template}.auradoc`),
this.destinationPath(
path.join(outputdir, componentname, `${componentname}.auradoc`)
),
{}
),
this.fs.copyTpl(
this.templatePath(`${template}.cmp`),
this.destinationPath(
path.join(outputdir, componentname, `${componentname}.cmp`)
),
{}
);
this.fs.copyTpl(
this.templatePath(`${template}.cmp`),
this.destinationPath(
path.join(outputdir, componentname, `${componentname}.cmp`)
),
this.fs.copyTpl(
this.templatePath('DefaultLightningCss.css'),
this.destinationPath(
path.join(outputdir, componentname, `${componentname}.css`)
),
{}
{}
);
this.fs.copyTpl(
this.templatePath(`${template}.css`),
this.destinationPath(
path.join(outputdir, componentname, `${componentname}.css`)
),
this.fs.copyTpl(
this.templatePath('DefaultLightningDesign.design'),
this.destinationPath(
path.join(outputdir, componentname, `${componentname}.design`)
),
{}
{}
);
this.fs.copyTpl(
this.templatePath(`${template}.design`),
this.destinationPath(
path.join(outputdir, componentname, `${componentname}.design`)
),
this.fs.copyTpl(
this.templatePath('DefaultLightningSVG.svg'),
this.destinationPath(
path.join(outputdir, componentname, `${componentname}.svg`)
),
{}
{}
);
this.fs.copyTpl(
this.templatePath(`${template}.svg`),
this.destinationPath(
path.join(outputdir, componentname, `${componentname}.svg`)
),
this.fs.copyTpl(
this.templatePath('DefaultLightningController.js'),
this.destinationPath(
path.join(outputdir, componentname, `${componentname}Controller.js`)
),
{}
{}
);
this.fs.copyTpl(
this.templatePath(`${template}Controller.js`),
this.destinationPath(
path.join(outputdir, componentname, `${componentname}Controller.js`)
),
this.fs.copyTpl(
this.templatePath('DefaultLightningHelper.js'),
this.destinationPath(
path.join(outputdir, componentname, `${componentname}Helper.js`)
),
{}
{}
);
this.fs.copyTpl(
this.templatePath(`${template}Helper.js`),
this.destinationPath(
path.join(outputdir, componentname, `${componentname}Helper.js`)
),
this.fs.copyTpl(
this.templatePath('DefaultLightningRenderer.js'),
this.destinationPath(
path.join(outputdir, componentname, `${componentname}Renderer.js`)
),
{}
);
{}
);
this.fs.copyTpl(
this.templatePath(`${template}Renderer.js`),
this.destinationPath(
path.join(outputdir, componentname, `${componentname}Renderer.js`)
),
{}
);
}
// tslint:disable-next-line:no-unused-expression
if (type === 'lwc') {
// lwc requires first letter of filename to be lowercase
const fileName = `${componentname
Expand All @@ -129,23 +148,30 @@ export default class LightningComponentGenerator extends SfdxGenerator<
.toUpperCase()}${componentname.substring(1)}`;

this.sourceRoot(
path.join(__dirname, '..', 'templates', 'lightningcomponent', 'lwc')
path.join(
__dirname,
'..',
'templates',
'lightningcomponent',
'lwc',
template
)
);
this.fs.copyTpl(
this.templatePath('DefaultLightningLWC.js'),
this.templatePath(`${template}.js`),
this.destinationPath(path.join(outputdir, fileName, `${fileName}.js`)),
{ className }
),
this.fs.copyTpl(
this.templatePath('_.html'),
this.destinationPath(
path.join(outputdir, fileName, `${fileName}.html`)
),
{}
);
);
this.fs.copyTpl(
this.templatePath(`${template}.html`),
this.destinationPath(
path.join(outputdir, fileName, `${fileName}.html`)
),
{}
);
if (!internal) {
this.fs.copyTpl(
this.templatePath('_js-meta.xml'),
this.templatePath(`${template}.js-meta.xml`),
this.destinationPath(
path.join(outputdir, fileName, `${fileName}.js-meta.xml`)
),
Expand Down
2 changes: 2 additions & 0 deletions packages/templates/src/i18n/i18n.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ export const messages = {
"Analytics templates must have a parent folder named 'waveTemplates'.",
MissingAuraDir: "Lightning bundles must have a parent folder named 'aura'.",
MissingLWCDir: "Lightning bundles must have a parent folder named 'lwc'.",
MissingLightningComponentTemplate:
'Template %s not available for component type %s.',

LightningAppBundle: 'A Lightning Application Bundle',
LightningComponentBundle: 'A Lightning Component Bundle',
Expand Down
29 changes: 29 additions & 0 deletions packages/templates/src/utils/createUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,33 @@ export class CreateUtil {
});
return files;
}

/** Get the names of directories that contain matching template files.
* This will look in directories under the command/subdir folder.
* @param command the command name
* @param filetype optional file name pattern to match on in the subdirectories
* @param subdir optional subdirectory under `templates/${command}`
* @return the set of template names
*/
public static getCommandTemplatesInSubdirs(
command: string,
{ filetype, subdir }: { filetype?: RegExp; subdir?: string } = {}
): string[] {
let basedir = path.resolve(__dirname, '..', 'templates', command);
if (subdir) {
basedir = path.join(basedir, subdir);
}
const subdirs = fs
.readdirSync(basedir, { withFileTypes: true })
.filter(ent => ent.isDirectory())
.map(ent => ent.name);
if (filetype) {
return subdirs.filter(dir =>
fs
.readdirSync(path.join(basedir, dir), { withFileTypes: true })
.some(ent => ent.isFile() && filetype.test(ent.name))
);
}
return subdirs;
}
}
Loading

0 comments on commit 0648ff5

Please sign in to comment.