/** * Configuration for validating that a script's body contains required substrings. * * @alpha */ export interface ScriptMustContainRule { /** * The name of the script to validate. */ script: string; /** * Substrings that must appear in the script body. * All substrings must be present for the script to pass validation. */ mustContain: string[]; } /** * Configuration for conditional script requirements. * * @alpha */ export interface ConditionalScriptRule { /** * The script that triggers the requirement. * If this script exists, then `requires` must also exist. */ ifPresent: string; /** * Scripts that must be present if `ifPresent` script exists. * * @remarks * * Each entry can be: * - A string: Script must exist, no auto-fix available * - An object `{ scriptName: "default value" }`: Script must exist, auto-fix adds the * default value if missing * * @example * ```typescript * requires: ["test", { clean: "rimraf dist" }] * ``` */ requires: RequiredScriptEntry[]; } /** * A required script entry. Can be either: * - A string (script name only, no default value) * - An object with a single key-value pair (script name → default value) * * @example * ```typescript * // Script must exist, no auto-fix available * "test" * * // Script must exist, auto-fix will add this value if missing * { lint: "biome lint ." } * ``` * * @alpha */ export type RequiredScriptEntry = string | Record; /** * Policy settings for the PackageScripts repo policy. * * @alpha */ export interface PackageScriptsSettings { /** * Scripts that must be present in package.json. * * @remarks * * Each entry can be: * - A string: Script must exist, no auto-fix available, content not validated * - An object `{ scriptName: "default value" }`: Script must exist, auto-fix adds the * default value if missing, but existing scripts with different content still pass * * @example * ```typescript * must: [ * "test", // Must exist, no auto-fix * { lint: "biome lint ." }, // Must exist, auto-fix available * { clean: "rimraf dist esm" }, // Must exist, auto-fix available * ] * ``` */ must?: RequiredScriptEntry[]; /** * Scripts that must exist AND have exact content. * * @remarks * * Unlike {@link PackageScriptsSettings.must}, scripts in `exact` are validated against * the specified value. If a script exists but has different content, it fails validation. * Both missing and mismatched scripts are auto-fixable. * * @example * ```typescript * exact: { * clean: "rimraf dist esm", * format: "biome format --write .", * } * ``` */ exact?: Record; /** * List of mutually exclusive script groups. Each group is an array of script names * where at most one script from the group can be present. * * Packages can have zero scripts from the group (all optional), but cannot have * multiple scripts from the same group. * * @example * ```typescript * // Allow "test:unit" OR "test:vitest" OR neither, but not both * mutuallyExclusive: [["test:unit", "test:vitest"]] * ``` */ mutuallyExclusive?: string[][]; /** * Conditional script requirements. If a script is present, other scripts must also exist. * * @remarks * * This is useful for enforcing that packages with a "build" script also have a "clean" script, * or packages with "test" also have "test:coverage". * * The `requires` field accepts the same format as {@link PackageScriptsSettings.must}: * - Strings: Script must exist, no auto-fix available * - Objects `{ scriptName: "default" }`: Script must exist, auto-fix adds the default if missing * * @example * ```typescript * // If "build" exists, "clean" must also exist (with auto-fix default) * conditionalRequired: [{ ifPresent: "build", requires: [{ clean: "rimraf dist" }] }] * * // Mixed: "test" required without default, "clean" with default * conditionalRequired: [{ ifPresent: "build", requires: ["test", { clean: "rimraf dist" }] }] * ``` */ conditionalRequired?: ConditionalScriptRule[]; /** * Rules for validating script body content. * * @remarks * * This allows you to ensure that specific scripts contain required commands or patterns * without requiring an exact match. For example, requiring that the "clean" script uses * "rimraf" or that "build" includes "tsc". * * For exact content matching, use {@link PackageScriptsSettings.exact} instead. * * @example * ```typescript * scriptMustContain: [ * { script: "clean", mustContain: ["rimraf"] }, * { script: "build", mustContain: ["tsc"] }, * ] * ``` */ scriptMustContain?: ScriptMustContainRule[]; } /** * A RepoPolicy that validates package.json scripts based on configurable rules. * * @remarks * * This policy provides comprehensive script validation including: * - Required scripts that must be present (with optional defaults for auto-fix) * - Exact script content enforcement * - Mutually exclusive script groups (at most one can exist) * - Conditional requirements (if X exists, Y must also exist) * - Script body content validation (script must contain specific substrings) * * @example * ```typescript * import { makePolicy } from "repopo"; * import { PackageScripts } from "repopo/policies"; * * const config: RepopoConfig = { * policies: [ * makePolicy(PackageScripts, { * // Scripts that must exist * must: [ * "test", // Must exist, no auto-fix * { build: "tsc" }, // Must exist, auto-fix available * { lint: "biome lint ." }, // Must exist, auto-fix available * ], * // Scripts that must exist AND match exactly * exact: { * clean: "rimraf dist esm", * format: "biome format --write .", * }, * // If "build" exists, "clean" must also exist (with inline auto-fix default) * conditionalRequired: [{ ifPresent: "build", requires: [{ clean: "rimraf dist" }] }], * // Script body must contain these substrings * scriptMustContain: [{ script: "build", mustContain: ["tsc"] }], * // Only one of these can exist * mutuallyExclusive: [["lint:eslint", "lint:biome"]], * }), * ], * }; * ``` * * @alpha */ export declare const PackageScripts: import("../policy.js").PolicyShape; //# sourceMappingURL=PackageScripts.d.ts.map