Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

picklist:unrestrict handle every objects paths #137

Merged
merged 2 commits into from
Jan 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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