@salesforce/plugin-templates
Version:
Commands to create metadata from a default or custom template
132 lines • 5.48 kB
JavaScript
/*
* Copyright (c) 2025, salesforce.com, inc.
* All rights reserved.
* Licensed under the BSD 3-Clause license.
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/
import path from 'node:path';
import fs from 'node:fs/promises';
import { Flags, SfCommand, Ux } from '@salesforce/sf-plugins-core';
import { TemplateType } from '@salesforce/templates';
import { Messages, SfProject } from '@salesforce/core';
import { getCustomTemplates, runGenerator } from '../../../../utils/templateCommand.js';
Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
const messages = Messages.loadMessages('@salesforce/plugin-templates', 'ui-bundle.generate');
export const UI_BUNDLES_DIR = 'uiBundles';
const GRAPHQLRC_FILENAME = '.graphqlrc.yml';
export default class UiBundleGenerate extends SfCommand {
static summary = messages.getMessage('summary');
static description = messages.getMessage('description');
static examples = messages.getMessages('examples');
static flags = {
name: Flags.string({
char: 'n',
summary: messages.getMessage('flags.name.summary'),
description: messages.getMessage('flags.name.description'),
required: true,
}),
template: Flags.string({
char: 't',
summary: messages.getMessage('flags.template.summary'),
description: messages.getMessage('flags.template.description'),
default: 'default',
options: ['default', 'reactbasic', 'angularbasic'],
}),
label: Flags.string({
char: 'l',
summary: messages.getMessage('flags.label.summary'),
description: messages.getMessage('flags.label.description'),
}),
'output-dir': Flags.directory({
char: 'd',
summary: messages.getMessage('flags.output-dir.summary'),
description: messages.getMessage('flags.output-dir.description'),
}),
'api-version': Flags.orgApiVersion(),
};
/**
* Resolves the default output directory by reading the project's sfdx-project.json.
* Returns the path to uiBundles under the default package directory,
* or falls back to the current directory if not in a project context.
*/
static async getDefaultOutputDir() {
try {
const project = await SfProject.resolve();
const defaultPackage = project.getDefaultPackage();
return path.join(defaultPackage.path, 'main', 'default', UI_BUNDLES_DIR);
}
catch {
return '.';
}
}
/**
* Creates a new `.graphqlrc.yml` at the sfdx project root so the GraphQL LSP extension
* can auto-discover it. The file at the project root references `schema.graphql` as a
* sibling and uses a recursive glob for documents so nested ui-bundle src trees are picked up.
*
* Returns the new file path on success, or undefined when not running inside an sfdx project,
* when the bundle's `.graphqlrc.yml` was not generated, or when a `.graphqlrc.yml` already
* exists at the project root.
*/
static async createGraphqlrcAtProjectRoot(bundleSourcePath) {
let projectRoot;
try {
const project = await SfProject.resolve();
projectRoot = project.getPath();
}
catch {
return undefined;
}
try {
await fs.access(bundleSourcePath);
}
catch {
return undefined;
}
const targetPath = path.join(projectRoot, GRAPHQLRC_FILENAME);
try {
await fs.access(targetPath);
return undefined;
}
catch {
// target does not exist — proceed
}
const content = "schema: 'schema.graphql'\ndocuments: './**/src/**/*.{graphql,js,ts,jsx,tsx}'\n";
await fs.writeFile(targetPath, content);
return targetPath;
}
async run() {
const { flags } = await this.parse(UiBundleGenerate);
const outputDir = flags['output-dir'] ?? (await UiBundleGenerate.getDefaultOutputDir());
const flagsAsOptions = {
bundlename: flags.name,
template: flags.template,
masterlabel: flags.label,
outputdir: outputDir,
apiversion: flags['api-version'],
};
const ux = new Ux({ jsonEnabled: this.jsonEnabled() });
const result = await runGenerator({
templateType: TemplateType.UIBundle,
opts: flagsAsOptions,
ux,
templates: getCustomTemplates(this.configAggregator),
});
if (flags.template === 'reactbasic') {
const bundleSourcePath = path.join(result.outputDir, flags.name, GRAPHQLRC_FILENAME);
const newPath = await UiBundleGenerate.createGraphqlrcAtProjectRoot(bundleSourcePath);
if (newPath) {
const targetRelative = path.relative(process.cwd(), newPath);
const createLine = ` create ${targetRelative}`;
ux.log(createLine);
return {
...result,
created: [...result.created, targetRelative],
rawOutput: `${result.rawOutput.replace(/\n$/, '')}\n${createLine}\n`,
};
}
}
return result;
}
}
//# sourceMappingURL=index.js.map