Skip to content

Commit

Permalink
Merge pull request #137 from nabondance/master
Browse files Browse the repository at this point in the history
picklist:unrestrict handle every objects paths
  • Loading branch information
FabienTaillon authored Jan 4, 2024
2 parents 8f64472 + 82d4ae4 commit 121ab31
Show file tree
Hide file tree
Showing 2 changed files with 88 additions and 35 deletions.
80 changes: 46 additions & 34 deletions src/commands/texei/picklist/unrestrict.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
} from '@salesforce/sf-plugins-core';
import { Messages, SfError } from '@salesforce/core';
import xml2js = require('xml2js');
import { getPackagesPaths, findObjectsFolders } from '../../../shared/sfdxProjectFolder';

// Initialize Messages with the current plugin directory
Messages.importMessagesDirectory(__dirname);
Expand Down Expand Up @@ -58,41 +59,52 @@ export default class Unrestrict extends SfCommand<PicklistUnrestrictResult> {

const picklistMetadata = [];

const filesPath = path.join(process.cwd(), 'force-app', 'main', 'default', 'objects');
const objectFolders = await fs.promises.readdir(filesPath, 'utf8');

for (const folder of objectFolders) {
// Excluse Custom Metadata
if (!folder.endsWith('__mdt')) {
const fieldsPath = path.join(filesPath, folder, 'fields');
if (fs.existsSync(fieldsPath)) {
const fieldsFolder = await fs.promises.readdir(fieldsPath, 'utf8');
for (const fieldFile of fieldsFolder) {
// Read File file
const fieldFilePath = path.join(fieldsPath, fieldFile);
const fieldData = await fs.promises.readFile(fieldFilePath, 'utf8');

// Parsing file
// According to xml2js doc it's better to recreate a parser for each file
// https://www.npmjs.com/package/xml2js#user-content-parsing-multiple-files
const parser = new xml2js.Parser({ explicitArray: false });
// eslint-disable-next-line @typescript-eslint/unbound-method
const parseString = util.promisify(parser.parseString);
// @ts-ignore: TODO: working code, but look at TS warning
const fieldJson = JSON.parse(JSON.stringify(await parseString(fieldData)));
if (
(fieldJson.CustomField.type === 'Picklist' || fieldJson.CustomField.type === 'MultiselectPicklist') &&
fieldJson.CustomField.valueSet?.valueSetName === undefined &&
fieldJson.CustomField.valueSet?.restricted === 'true'
) {
// Clean Json for update
const fieldMetadata = fieldJson.CustomField;
fieldMetadata.fullName = `${folder}.${fieldJson.CustomField.fullName}`;
fieldMetadata.valueSet.restricted = 'false';
delete fieldMetadata['$'];
delete fieldMetadata['@xsi:type'];
const objectsFolderPaths: string[] = [];
const EXCLUDED_DIRS = ['node_modules', '.git'];

// Get packages paths
const packagesPaths: string[] = await getPackagesPaths();

// Get all the objects folder paths inside the package ones
for (const recType of findObjectsFolders(packagesPaths, EXCLUDED_DIRS)) {
objectsFolderPaths.push(recType);
}

for (const objectsFolderPath of objectsFolderPaths) {
const objectFolders = await fs.promises.readdir(objectsFolderPath, 'utf8');
for (const folder of objectFolders) {
// Excluse Custom Metadata
if (!folder.endsWith('__mdt')) {
const fieldsPath = path.join(objectsFolderPath, folder, 'fields');
if (fs.existsSync(fieldsPath)) {
const fieldsFolder = await fs.promises.readdir(fieldsPath, 'utf8');
for (const fieldFile of fieldsFolder) {
// Read File file
const fieldFilePath = path.join(fieldsPath, fieldFile);
const fieldData = await fs.promises.readFile(fieldFilePath, 'utf8');

// Parsing file
// According to xml2js doc it's better to recreate a parser for each file
// https://www.npmjs.com/package/xml2js#user-content-parsing-multiple-files
const parser = new xml2js.Parser({ explicitArray: false });
// eslint-disable-next-line @typescript-eslint/unbound-method
const parseString = util.promisify(parser.parseString);
// @ts-ignore: TODO: working code, but look at TS warning
picklistMetadata.push(fieldMetadata);
const fieldJson = JSON.parse(JSON.stringify(await parseString(fieldData)));
if (
(fieldJson.CustomField.type === 'Picklist' || fieldJson.CustomField.type === 'MultiselectPicklist') &&
fieldJson.CustomField.valueSet?.valueSetName === undefined &&
fieldJson.CustomField.valueSet?.restricted === 'true'
) {
// Clean Json for update
const fieldMetadata = fieldJson.CustomField;
fieldMetadata.fullName = `${folder}.${fieldJson.CustomField.fullName}`;
fieldMetadata.valueSet.restricted = 'false';
delete fieldMetadata['$'];
delete fieldMetadata['@xsi:type'];
// @ts-ignore: TODO: working code, but look at TS warning
picklistMetadata.push(fieldMetadata);
}
}
}
}
Expand Down
43 changes: 42 additions & 1 deletion src/shared/sfdxProjectFolder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// ex. for record type: MyRecordTypeForAccount, MyRecordTypeForAccount.recordType-meta.xml, Account.MyRecordTypeForAccount
import * as path from 'path';
import * as fs from 'fs';
import { SfProjectJson } from '@salesforce/core';
import { NamedPackageDir, SfProject, SfProjectJson } from '@salesforce/core';
import { JsonArray, JsonMap } from '@salesforce/ts-types';
const defaultProjectFolder = 'force-app';
const defaultPackageFolder: string = path.join('force-app', 'main', 'default');
Expand All @@ -23,6 +23,47 @@ export function getMetadata(metadata: string): string[] {
return metadatas;
}

export async function getPackagesPaths(): Promise<string[]> {
try {
const project: SfProject = await SfProject.resolve();
const packageDirectories: NamedPackageDir[] = project.getPackageDirectories();

return packageDirectories.map((dir) => dir.path);
} catch (error) {
/* eslint-disable no-console */
console.error('Error retrieving package paths: ', error);
return [];
}
}

// Get all paths of objects folders with the possibility to exclude specific folders
export function findObjectsFolders(startPaths: string[], excludedDirs: string[] = []): string[] {
const result: string[] = [];
for (const iPath of startPaths) {
// the new loop on the new startPaths parameter
const filesAndDirs = fs.readdirSync(iPath);

for (const fileOrDir of filesAndDirs) {
const fullPath = path.join(iPath, fileOrDir);

if (fs.statSync(fullPath).isDirectory()) {
// If the directory is in the exclusion list, skip it.
if (excludedDirs.includes(fileOrDir)) {
continue;
}

if (fileOrDir === 'objects') {
result.push(fullPath);
}

result.push(...findObjectsFolders([fullPath], excludedDirs));
}
}
}

return result;
}

export function getFieldsForObject(objectName: string): string[] {
const fieldsPath = path.join('force-app', 'main', 'default', 'objects', objectName, 'fields');

Expand Down

0 comments on commit 121ab31

Please sign in to comment.