import type { Logger } from '@b64hub/sfpm-core'; import type { ComponentMap, OrgMetadataProvider, Profile, ProfileHooksOptions } from './types.js'; /** * Handles cleaning and scoping of Salesforce profile XML files. * * Profile scoping removes permission entries from profile XML that * don't correspond to metadata present in the package being deployed. * This prevents deployment failures caused by references to components * that don't exist in the target org. * * Migrated from {@link https://github.com/flxbl-io/sfprofiles | sfprofiles} * and adapted to work as a standalone cleaner. By default scoping is * source-only: permissions referencing metadata absent from the package are * removed. When an {@link OrgMetadataProvider} is provided, the cleaner also * checks the target org — preserving permissions for standard metadata that * exists in the org but not in the package source. * * @example * ```typescript * const cleaner = new ProfileCleaner({ scope: 'source', removeLoginIpRanges: true }); * const results = await cleaner.cleanProfiles('/path/to/profiles', knownComponents); * console.log(`Cleaned ${results.length} profile(s)`); * * // With org-aware scoping: * const orgResolver = new OrgMetadataResolver(connection, logger); * await cleaner.cleanProfiles('/path/to/profiles', knownComponents, orgResolver); * ``` */ export declare class ProfileCleaner { private readonly logger?; readonly options: Required; constructor(options?: ProfileHooksOptions, logger?: Logger | undefined); /** * Clean a single parsed {@link Profile} object in-place. * * Applies: * 1. Section scoping (remove entries referencing absent metadata) * 2. Login hours stripping * 3. Login IP range stripping * 4. Unassigned user permission stripping * * @param profile - The profile to clean * @param packageComponents - Package components grouped by profile section * @param orgComponents - Pre-resolved org components grouped by profile section. * When provided, these are merged with package components before scoping. * Use {@link resolveOrgComponents} to pre-fetch from an {@link OrgMetadataProvider}. * @returns The cleaned profile (same reference, mutated) */ cleanProfile(profile: Profile, packageComponents?: ComponentMap, orgComponents?: ComponentMap): Promise; /** * Clean all profile files in the given directory. * * Reads every `.profile-meta.xml` file, applies scoping and * stripping rules, then writes the cleaned XML back to disk. * * @param profilesDirectory - Absolute path to the profiles directory * @param packageComponents - Package components grouped by profile section. * When provided and `scope` is not `'none'`, profile sections referencing * components not in the matching section set are removed. * @param orgResolver - Optional org metadata provider. When provided (and * `scope` is `'org'`), components found in the target org are also * preserved during scoping. Queried once upfront and shared across all profiles. * @returns Array of file paths that were cleaned */ cleanProfiles(profilesDirectory: string, packageComponents?: ComponentMap, orgResolver?: OrgMetadataProvider): Promise; /** * Resolve org components for all profile sections in parallel. * * Call once and pass the result to {@link cleanProfile} to avoid * repeated org queries when cleaning multiple profiles. */ resolveOrgComponents(resolver: OrgMetadataProvider): Promise; /** * Filter items in a single profile section, keeping only those whose * referenced component exists in the known set for that section. */ private filterSectionItems; /** * Check whether a field permission's component is known. * * A field is kept only if the full qualified name (e.g. `Account.CustomField__c`) * exists in the field set. We intentionally do NOT fall back to checking * the parent object — a deleted field whose parent object still exists * would cause deployment failures. */ private isFieldKnown; /** * Check whether a layout assignment is known. * * The layout name must exist in the layout set. If a recordType is specified, * it must exist in either the layout set or the recordType set. */ private isLayoutKnown; /** * Merge two component maps. For each section, the result is the union of * both maps' sets for that section. */ private mergeComponentMaps; /** * Remove user permissions that have `enabled: false`. * * Standard profiles cannot have their userPermissions edited, so all * userPermissions are removed from non-custom profiles — mirroring the * sfprofiles behavior. */ private removeUnassignedPermissions; /** * For each profile section, filter out entries whose referenced component * name is not in the known component map for that section. * * When org components are provided, they are merged with package * components before filtering — preserving permissions for metadata that * is present in the org but not in the package source. */ private scopeSections; } /** * Find profile directories within a package's source path. * * Searches standard Salesforce directory structures for profile files. */ export declare function findProfilesDirectory(packagePath: string): string | undefined; /** * Collect metadata component names from a Salesforce source directory, * grouped by profile section. * * Walks standard metadata directories (classes, objects, pages, etc.) * and extracts component API names from file names. The results are * grouped by the profile section that references them, enabling * symmetric comparison with org metadata during profile scoping. * * @param packagePath - Root of the package source (e.g., `force-app/main/default`) * @returns Components grouped by profile section */ export declare function collectPackageComponents(packagePath: string): Promise;