import type { FileOperationResult, ProjectType } from "../core/config.js";
import type { ICopyStrategy, StrategyContext } from "./strategy.interface.js";
/**
 * @file package-lisa.ts
 * @description Package.lisa.json strategy for governance-driven package.json management
 *
 * Implements a two-file approach to package.json governance:
 * - Source: package.lisa.json files in type directories (all/, typescript/, expo/, etc.)
 * - Destination: project's package.json
 *
 * Behavior is defined in package.lisa.json:
 * - force: Lisa's values completely replace project's values
 * - adopt: Lisa reclaims a key still holding a value Lisa itself wrote
 * - defaults: Project's values preserved; Lisa's used only if missing
 * - merge: Arrays concatenated and deduplicated
 * - remove: Retired keys deleted from their section
 *
 * A governed script CI invokes is shipped as a pair — `lint:lisa` forced, and
 * `lint` merely defaulted to invoke it — so the host owns the composition point
 * and anything chained onto it survives an apply. See the reserved-base section
 * of `wiki/documentation/specs/package-lisa-json.md`.
 *
 * Inheritance chain: all → typescript → specific types (expo, nestjs, cdk, npm-package)
 * Child types override parent values in each section.
 * @module strategies
 */
/**
 * Package.lisa.json strategy: Manage package.json via separate template files
 * - Loads templates from all applicable types in inheritance chain
 * - Merges templates (child overrides parent)
 * - Applies force/defaults/merge logic to project's package.json
 * - Keeps project's package.json 100% clean (no Lisa artifacts)
 */
export declare class PackageLisaStrategy implements ICopyStrategy {
    private readonly readApplyingVersion;
    readonly name: "package-lisa";
    /**
     * Build a strategy, optionally stating the version performing the apply.
     * @param readApplyingVersion - Reports the Lisa version performing the apply.
     * Injected rather than read inline so a spec can state a version outright
     * instead of deriving its expectation from the code under test.
     */
    constructor(readApplyingVersion?: () => string);
    private readonly PACKAGE_JSON;
    private readonly TSCONFIG_JSON;
    private readonly APP_JSON;
    private readonly EAS_JSON;
    private readonly NEST_CLI_JSON;
    private readonly CDK_JSON;
    private readonly HARPER_APP_CONFIG;
    private readonly HARPER_APP_SCHEMA;
    /**
     * Produce the exact package.json result from already-safe project inputs.
     * @param projectJson - Parsed host package.json
     * @param detectedTypes - Canonically detected project types
     * @param lisaDir - Lisa package root
     * @param securityPinsOnly - Restrict to postinstall-safe security pins
     * @returns Package document that apply would persist
     */
    planPackageJson(projectJson: Record<string, unknown>, detectedTypes: readonly ProjectType[], lisaDir: string, securityPinsOnly?: boolean): Promise<Record<string, unknown>>;
    /**
     * Apply package-lisa strategy: Load templates from inheritance chain, apply to package.json
     * @remarks
     * This strategy is unique because:
     * 1. It loads multiple source files from type hierarchy, not just one
     * 2. It applies structured merge logic (force/defaults/merge) instead of simple JSON merge
     * 3. It never applies changes if source file doesn't exist in ANY type directory
     * 4. Source is package.lisa.json but destination is always package.json
     * @param sourcePath - Path to source package.lisa.json (triggers the strategy)
     * @param destPath - Passed as package.lisa.json path, but we target package.json instead
     * @param relativePath - Passed as package.lisa.json, but we record package.json
     * @param context - Strategy context with config and callbacks
     * @returns Result with action "copied", "merged", or "skipped"
     */
    apply(sourcePath: string, destPath: string, relativePath: string, context: StrategyContext): Promise<FileOperationResult>;
    /**
     * Create destination file when it doesn't exist
     * @param destPath - Path to destination package.json
     * @param merged - Merged package.json object
     * @param relativePath - Relative path for recording
     * @param context - Strategy context with config and callbacks
     * @param notes - Operator-visible notes explaining non-obvious rewrites
     * @returns Result with action "copied"
     * @private
     */
    private createDestination;
    /**
     * Update destination file when it exists
     * @param destPath - Path to destination package.json
     * @param merged - Merged package.json object
     * @param relativePath - Relative path for recording
     * @param context - Strategy context with config and callbacks
     * @param notes - Operator-visible notes explaining non-obvious rewrites
     * @returns Result with action "merged" or "skipped"
     * @private
     */
    private updateDestination;
    /**
     * Merge package.json using force/defaults/merge logic from package.lisa.json templates
     * @param packageJsonPath - Absolute path to destination package.json
     * @param context - Strategy context with Lisa config
     * @param securityPinsOnly - When true (skip-git-check on an existing package.json),
     *   apply only force.resolutions/force.overrides and preserve all other host config
     * @returns Planned package.json object plus operator-visible notes
     * @private
     */
    private mergePackageJson;
    /**
     * Reduce a resolved template to only the security-critical sections —
     * `force.resolutions` and `force.overrides`, plus the retirements aimed at
     * those same two sections — dropping force.scripts, defaults, merge, and
     * every other retirement. Used during skip-git-check (postinstall) applies so
     * dependency pins still apply without clobbering host config.
     *
     * Retiring an override is as security-critical as writing one, so it travels
     * with them. Dropping it left a pin that turns out to be harmful with no way
     * to reach a host through postinstall: the template stops forcing the key,
     * but the copy already written into the host's package.json stays. That is
     * how `brace-expansion >=5.0.9` would have survived its own removal.
     * Retirements aimed at other sections stay behind, because deleting host
     * scripts or dependencies is exactly the config clobbering this path avoids.
     *
     * The retained overrides/resolutions may contain `$name` self-references or
     * literal pins that normalize to `$name` later. Both resolve against a direct
     * dependency of that name. If the restricted template drops the backing direct
     * dep, postinstall can validate against the host's wider range and fail the
     * normalization guard. So we also pull the package's forced pin from
     * force.dependencies / force.devDependencies into the restricted set.
     * @param template - Fully merged template from the type hierarchy
     * @returns Template carrying force.resolutions/force.overrides, the direct
     *   dependencies that back any direct-dependency override within them, and
     *   the retirements aimed at those same two sections
     * @private
     */
    private restrictToSecurityPins;
    /**
     * For every direct-dependency override in the restricted overrides/resolutions,
     * copy the forced pin for `name` from the full template's force.dependencies /
     * force.devDependencies into the restricted force section so the backing direct
     * dependency is materialized. A devDependencies pin wins over dependencies when
     * both exist.
     * @param template - Fully merged template (source of the forced dep pins)
     * @param force - Restricted force section being assembled (mutated in place)
     * @private
     */
    private includeBackingDirectDeps;
    /**
     * Detect which project types apply to this project
     * (TypeScript, Expo, NestJS, CDK, Harper/Fabric, npm-package)
     * @param projectDir - Root directory of the project
     * @returns Array of detected project types
     * @private
     */
    private detectProjectTypes;
    /**
     * Check whether harper-app/config.yaml declares the expected Harper component
     * resource keys.
     * @param projectDir - The project directory to check
     * @returns True if the config has Harper/Fabric component signals
     * @private
     */
    private harperConfigHasComponentSignals;
    /**
     * Check if package.json dependencies/devDependencies contain a specific package
     * @param projectDir - The project directory to check
     * @param packageName - The exact package name to check for (e.g., "typescript", "expo")
     * @returns True if the package is in dependencies or devDependencies, false otherwise
     * @private
     */
    private packageJsonHasDependency;
    /**
     * Check if package.json dependencies/devDependencies contain a package starting with prefix
     * @param projectDir - The project directory to check
     * @param prefix - The prefix to check for (e.g., "@nestjs", "aws-cdk")
     * @returns True if any dependency starts with the given prefix, false otherwise
     * @private
     */
    private packageJsonHasDependencyPrefix;
    /**
     * Get a field value from package.json
     * @param projectDir - The project directory containing the package.json
     * @param fieldName - The field name to retrieve from package.json
     * @returns The field value if found, undefined if not found or if package.json doesn't exist
     * @private
     */
    private packageJsonField;
    /**
     * Load and merge all package.lisa.json templates from type hierarchy
     * @remarks
     * Inheritance chain: all → typescript → specific types (expo, nestjs, cdk, npm-package)
     * Child types override parent types in force, defaults, and merge sections.
     * @param lisaDir - Root Lisa directory path
     * @param detectedTypes - Project types to load templates for
     * @returns Merged template with force, defaults, merge sections
     * @private
     */
    private loadAndMergeTemplates;
    /**
     * Expand project types to include parent types, sorted by hierarchy order
     * @remarks
     * Type hierarchy: expo/nestjs/cdk/npm-package inherit from typescript
     * This expands a list to include parents and sorts by PROJECT_TYPE_ORDER
     * so parents are processed before children (enabling child overrides).
     * Example: [cdk] → [typescript, cdk]
     * @param types - Project types detected
     * @returns Expanded types including parents, sorted parents-first
     * @private
     */
    private expandTypeHierarchy;
    /**
     * Merge two template objects
     * Child template (override) values win in force and defaults.
     * Merge and remove arrays are concatenated without deduplication at merge time.
     * @param parent - Parent template (e.g., "all" or "typescript")
     * @param child - Child template (e.g., "expo") that overrides parent
     * @returns Merged template
     * @private
     */
    private mergeTemplates;
    /**
     * Merge two merge-section objects
     * Arrays are concatenated (deduplication happens later when applied to package.json)
     * @param parent - Parent merge sections
     * @param child - Child merge sections
     * @returns Merged sections
     * @private
     */
    private mergeMergeSections;
    /**
     * Apply force/defaults/merge/remove logic to project's package.json
     * @remarks
     * Processing order:
     * 1. Apply force: Deep merge with Lisa values winning (entire section replaced)
     * 2. Apply defaults: Deep merge with project values winning (only set if missing)
     * 3. Apply merge: Concatenate arrays and deduplicate
     * 4. Apply remove: Delete retired keys from their sections (runs last so an
     *    earlier phase cannot reintroduce a removed key)
     * @param projectJson - Current project's package.json
     * @param template - Merged package.lisa.json template
     * @param fileName - Basename used in error messages
     * @param restricted - True when the template was reduced to security pins,
     *   which is the postinstall path and Lisa's own repository
     * @returns Modified package.json plus operator-visible notes
     * @private
     */
    private applyTemplate;
    /**
     * Delete retired keys from their package.json sections
     * @remarks
     * Used to clean up keys Lisa previously forced and has since renamed or
     * retired (e.g. the "knip" script renamed to "knip:check"). Runs after
     * force/defaults/merge so a removed key cannot be reintroduced within the
     * same apply. Sections that don't exist or aren't objects are left alone.
     * @param packageJson - Current package.json after force/defaults/merge applied
     * @param removeSections - Map of section name to keys to delete from it
     * @returns Package.json with retired keys removed
     * @private
     */
    private applyRemoveSections;
    /**
     * Apply merge-section arrays to package.json
     * Concatenates Lisa's items and project's items, deduplicated by JSON.stringify equality.
     * @param packageJson - Current package.json after force/defaults applied
     * @param mergeSections - Merge sections from template
     * @returns Package.json with merge sections applied
     * @private
     */
    private applyMergeSections;
    /**
     * Concatenate two arrays and remove duplicates
     * Uses JSON.stringify for value equality comparison.
     * Lisa items come first, then project's unique items.
     * @param lisaItems - Lisa's items (come first)
     * @param projectItems - Project's items (added if not already present)
     * @returns Deduplicated array
     * @private
     */
    private deduplicateArrays;
}
//# sourceMappingURL=package-lisa.d.ts.map