UNPKG

@salesforce/acu-pack

Version:
273 lines 12 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const command_1 = require("@salesforce/command"); const command_base_1 = require("../../../lib/command-base"); const options_factory_1 = require("../../../lib/options-factory"); const utils_1 = require("../../../lib/utils"); const scaffold_options_1 = require("../../../lib/scaffold-options"); const sfdx_project_1 = require("../../../lib/sfdx-project"); const sfdx_tasks_1 = require("../../../lib/sfdx-tasks"); class Scaffold extends command_base_1.CommandBase { constructor() { super(...arguments); this.schemas = new Map(); this.index = 0; } async runInternal() { let options; // Read/Write the options file if it does not exist already if (this.flags.options) { options = await options_factory_1.OptionsFactory.get(scaffold_options_1.ScaffoldOptions, this.flags.options); if (!options) { this.raiseError(`Unable to read options file: ${this.flags.options}.`); } } else { options = new scaffold_options_1.ScaffoldOptions(); await options.loadDefaults(); } if (this.flags.sobjects) { options.sObjectTypes.push(...this.flags.sobjects.split(',')); } this.ux.log('Retrieving Schemas...'); for (const sObjectType of options.sObjectTypes) { await this.getSchema(sObjectType.replace(' ', '')); } this.ux.log('Reading ./sfdx-project.json file...'); const project = await sfdx_project_1.default.default(); const defaultFolder = project.getDefaultDirectory(); this.ux.log('Generating Apex cls & cls-meta files...'); const rootPath = `./${defaultFolder}/main/default/classes/`; await utils_1.default.mkDirPath(rootPath); for (const [schemaName, schema] of this.schemas) { this.ux.log('\t' + schemaName); const fileDetails = this.generateTestSetupCode(schemaName, schema, options); await utils_1.default.writeFile(rootPath + `${fileDetails.name}.cls`, fileDetails.contents); await utils_1.default.writeFile(rootPath + `${fileDetails.name}.cls-meta.xml`, Scaffold.META_XML.replace(/API_VERSION_TOKEN/, project.sourceApiVersion)); } } async getSchema(sObjectType) { let schema = this.schemas.get(sObjectType); if (!schema) { schema = await sfdx_tasks_1.SfdxTasks.describeObject(this.orgAlias, sObjectType); if (!schema) { this.raiseError('The returned schema is null.'); } if (!schema.fields) { this.raiseError('The returned schema does not contain a fields member.'); } this.schemas.set(schema.name.split('__')[0], schema); } /* eslint-disable-next-line @typescript-eslint/no-unsafe-return */ return schema; } generateTestSetupCode(simpleName, schema, options) { // Don't exceed max class name length const noUnderscoreName = simpleName.replace(/_/g, ''); const className = `${noUnderscoreName.substring(0, Scaffold.MAX_CLASS_NAME_LENGTH - 4)}Test`; const varName = `${className.substring(0, 1).toLowerCase()}${className.substring(1)}`; const pre = '\t\t\t'; const classLines = [ '// This class was generated by the acu-pack:apex:scaffold command.', '@IsTest', `public with sharing class ${className} {`, '', '\t@TestSetup', '\tstatic void setupTestData() {', '\t\t// Create instance', `\t\t${schema.name} ${varName} = new ${schema.name}( `, ]; const codeLines = new Map(); for (const field of schema.fields) { // Skip optional fields? if (!options.includeOptionalFields && field.nillable) { continue; } if (field.createable) { const value = options.includeRandomValues ? this.generateFieldValue(field) : null; codeLines.set(field.name, `${pre}${field.name} = ${value}`); } } const sortedKeys = utils_1.default.sortArray(Array.from(codeLines.keys())); for (const key of sortedKeys) { let classLine = codeLines.get(key); if (key !== sortedKeys[sortedKeys.length - 1]) { classLine += ','; } classLines.push(classLine); } classLines.push(...['\t\t);', `\t\tinsert ${varName};`, '\t}', '}']); return { name: className, contents: classLines.join('\n'), }; } generateFieldValue(field) { // https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_variables_global_objecttype_schema_fields_reference.htm if (!field) { this.raiseError('The field argument cannot be null.'); } const noUnderscoreName = field.name.split('__')[0].replace(/_/g, ''); const getStr = (fld, maxLength) => { if (!fld) { this.raiseError('The fld argument cannot be null.'); } const value = fld.name; let strLen = fld.length; if (!strLen || strLen === 0 || strLen > maxLength) { strLen = maxLength; } // trim if we are too long if (strLen && value.length > strLen) { return value.substr(0, strLen); } return value; }; const getDec = (fld, maxLength) => { if (!fld) { this.raiseError('The fld argument cannot be null.'); } let num = ''; let numLen = fld.precision; if (!numLen || numLen === 0 || numLen > maxLength) { numLen = maxLength; } const scale = fld.scale ?? 0; for (let index = 1; index <= numLen - scale; index++) { num += get1Rand(); } if (fld.scale > 0) { num += '.'; for (let index = 1; index <= scale; index++) { num += get1Rand(); } } return num; }; const getRand = (min, max) => { return Math.floor(Math.random() * (max - min) + min); }; const get1Rand = () => { return getRand(0, 9); }; const getPicklist = (picklistValues, count) => { const values = []; const index = getRand(0, picklistValues.length); for (const picklist of picklistValues.slice(index)) { if (!picklist.active) { continue; } values.push(picklist.value); if (values.length === count) { return values; } } return null; }; const getValue = (fld) => { if (!fld) { this.raiseError('The fld argument cannot be null.'); } switch (fld.type) { case 'anytype': case 'string': case 'encryptedString': case 'textarea': return `'${getStr(fld)}'`; case 'base64': return `'${Buffer.from(getStr(fld)).toString('base64')}'`; case 'textarea1': { const lineCount = 3; // Calculate length of each line (subract for \n) then divide const lineLength = Math.floor((fld.length - lineCount) / 3); const lines = []; for (let lineIndex = 0; lineIndex < lineCount; lineIndex++) { lines.push(`${getStr(fld, lineLength)}`); } return lines.join('+\n'); } case 'int': case 'integer': return `${getDec(fld, 10)}`; case 'long': return `${getDec(fld, 16)}L`; case 'double': case 'percent': return `${getDec(fld, 10)}`; case 'currency': return `${getDec(fld)}`; case 'address': return `'123 ${fld.name} St.'`; case 'boolean': return `${Math.random() < 0.5 ? 'true' : 'false'}`; case 'date': return 'Date.today()'; case 'datetime': return 'Datetime.now()'; case 'time': return 'Datetime.getTime()'; case 'email': return `'${fld.name}@${noUnderscoreName}.email.org'`; case 'phone': { const phone = `555-${getRand(100, 999)}-${getRand(1000, 9999)} ext ${++this.index}`; // phone max is 40 return `'${phone.substr(0, 40)}'`; } case 'multipicklist': { if (fld.picklistValues?.length === 0) { this.ux.log(`Skipping: ${fld.name} (${fld.type}) - no picklist values.`); } const count = Math.floor(fld.picklistValues.length / 3); const values = getPicklist(fld.picklistValues, count); return values ? `'${values.join(';').replace(/'/g, "\\'")}'` : null; } case 'picklist': { if (fld.picklistValues?.length === 0) { this.ux.log(`Skipping: ${fld.name} (${fld.type}) - no picklist values.`); } const value = getPicklist(fld.picklistValues, 1); return value ? `'${value.join(';').replace(/'/g, "\\'")}'` : null; } case 'url': return `'https://www.${noUnderscoreName}.salesforce.com.${this.orgAlias}/index'`; case 'id': case 'reference': case 'combobox': case 'dataCategoryGroupReference': default: this.ux.log(`Skipping: ${fld.name} (${fld.type})`); return null; } }; return getValue(field); } } exports.default = Scaffold; Scaffold.description = command_base_1.CommandBase.messages.getMessage('apex.scaffold.commandDescription'); Scaffold.examples = [ `$ sfdx acu-pack:apex:scaffold -u myOrgAlias -s Account,MyObject__c' Generates AccountTest.cls & MyObjectTest.cls Apex test classes (and cls-meta files) for the Account & MyObject__c SObject types. Random values assigned to required fields by default`, `$ sfdx acu-pack:apex:scaffold -u myOrgAlias -o scaffold-options.json Generates Apex test classes (and cls-meta files) for specified CustomObjects. The specified options file is used.`, ]; Scaffold.flagsConfig = { sobjects: command_1.flags.string({ char: 's', description: command_base_1.CommandBase.messages.getMessage('apex.scaffold.sObjectsFlagDescription'), }), options: command_1.flags.string({ char: 'o', description: command_base_1.CommandBase.messages.getMessage('apex.scaffold.optionsFlagDescription'), }), }; // Comment this out if your command does not require an org username Scaffold.requiresUsername = true; // Set this to true if your command requires a project workspace; 'requiresProject' is false by default Scaffold.requiresProject = true; Scaffold.META_XML = '<?xml version="1.0" encoding="UTF-8"?>\n' + '<ApexClass xmlns="http://soap.sforce.com/2006/04/metadata">\n' + '<apiVersion>API_VERSION_TOKEN</apiVersion>\n' + '<status>Active</status>\n' + '</ApexClass>'; Scaffold.MAX_CLASS_NAME_LENGTH = 40; //# sourceMappingURL=scaffold.js.map