/**
* Pure helper: compute the desired `html.customData` array for a project.
*
* Returns `null` when no change is required (the existing array already matches),
* otherwise the new array that should be written.
*
* The produced entry is a project-relative path with forward slashes. We use
* `path.relative` rather than a string replace because Vite normalises projectRoot
* to forward slashes while `htmlDataPath` carries the platform separator from
* `path.join` — a naive replace fails to match on Windows and leaves an absolute path.
* Any pre-existing entry pointing at a `needle-html-data.json` (e.g. an absolute path
* written by an older version of this plugin) is dropped so we don't accumulate
* duplicates or leave stale absolute paths behind.
*
* Exported for testing. The `relativeFn` seam lets tests reproduce platform-specific
* separator behaviour (`path.win32.relative` / `path.posix.relative`) deterministically.
*
* @param {unknown[]} existing Current html.customData entries
* @param {string} projectRoot
* @param {string} htmlDataPath Absolute path to the generated needle-html-data.json
* @param {(from: string, to: string) => string} [relativeFn]
* @returns {string[] | null}
*/
export function computeHtmlCustomData(existing: unknown[], projectRoot: string, htmlDataPath: string, relativeFn?: (from: string, to: string) => string): string[] | null;
/**
* @param {"build" | "serve"} _command Vite command (unused — runs in both modes)
* @param {import('../types/needleConfig').needleMeta | null | undefined} _config
* @param {import('../types').userSettings} [_userSettings]
* @returns {import('vite').Plugin | null}
*/
export function needleDtsGenerator(_command: "build" | "serve", _config: import("../types/needleConfig").needleMeta | null | undefined, _userSettings?: import("../types").userSettings): import("vite").Plugin | null;