/** * Removal of suppression entries from a model's suppression list * ({Model}_BPSuppressions.xml, in the AxIgnoreDiagnosticList metadata FOLDER). * * The file's own ROOT ELEMENT is — confirmed against a real * production suppression file — not * ... as an * earlier version of this module assumed by analogy with every other Ax* type's * folder-name-matches-root-element convention. and are direct * children of that root; blocks are direct children of , one * level shallower than first assumed. That first guess was flagged UNVERIFIED in * this module's own docs at the time and was wrong — this is the corrected, * measured shape. * * is a flat list of blocks — no nesting, same shape as * AxSecurityPrivilege's — so this mirrors removeSecurityEntryPoint * in securityPrivilegeXml.ts: regex-scan the flat blocks, match by (the * field BP-check itself uses to key a suppression, so it is the only identifier * guaranteed unique-per-rule-and-target), refuse rather than guess when a path * carries more than one diagnostic, and splice by byte offset. * * alone is not always unique: the same dynamics:// target can be ignored * by more than one moniker (an unresolved-label warning AND a doc-comment warning * on the same field, say) — `moniker` narrows that case the same way * entryPointObjectType narrows a duplicate objectName on a security privilege. */ /** One suppression entry as written into . */ export interface DiagnosticSuppressionEntry { /** — the dynamics:// target the finding was raised against. */ path: string; /** — the BP rule this entry silences. */ moniker: string; } export type RemoveDiagnosticSuppressionResult = /** Removed. `removed` is the entry that went, `xml` the updated document. */ { kind: 'removed'; xml: string; removed: DiagnosticSuppressionEntry; } /** No diagnostic matched `path` (+ `moniker`). `present` lists the ones there are. */ | { kind: 'not-found'; present: DiagnosticSuppressionEntry[]; } /** More than one diagnostic matches — refuse rather than pick. */ | { kind: 'ambiguous'; matches: DiagnosticSuppressionEntry[]; } /** Not a suppression list (no root); the caller declines. */ | { kind: 'unsupported'; }; /** * Remove one from a suppression list by exact match, * optionally narrowed by when the same path carries more than one * suppression. * * Two matches are refused rather than resolved: deleting the wrong one leaves a * live BP finding suppressed and silences the one that should have surfaced. * * When the last diagnostic goes, is collapsed to the self-closing spelling. */ export declare function removeDiagnosticSuppression(xml: string, criteria: { path: string; moniker?: string; }): RemoveDiagnosticSuppressionResult; export type AddDiagnosticSuppressionResult = /** Inserted. `xml` is the updated document. */ { kind: 'added'; xml: string; } /** An entry with the SAME and is already there — refuse a * second copy of a suppression that already silences this exact finding. */ | { kind: 'duplicate'; existing: DiagnosticSuppressionEntry; } /** Not a suppression list (no root); the caller declines. */ | { kind: 'unsupported'; } /** A suppression list, but with no collection to insert into — there is * nowhere to put the entry, and reporting success would write the file back * byte-identical under a ✅. */ | { kind: 'no-items'; }; /** * Insert one block (as rendered by buildSuppressionXml in * bpMonikers/index.ts — the caller builds it, this only places it) into a * suppression list's . * * Refuses a duplicate — same AND — rather than writing a * second copy: xppbp does not need two identical suppressions, and a caller * who does not know one already exists benefits far more from being told than * from a file that silently grows a redundant entry every time they re-run * the same suppress call. * * Whitespace here is cosmetic, unlike buildAxSecurityPrivilegeXml's element * ORDER: is an unordered bag of sibling blocks, so this * matches an existing entry's indentation when there is one, and falls back to * a plausible default (two levels deep — is a direct child of * , itself a direct child of the root , confirmed * against a real production file) for the first entry in a file — it does not * have to byte-match Microsoft's serializer the way an element order would, * because whitespace between elements does not change what deserializes. * * An empty is spelled BOTH ways in a shipped PackagesLocalDirectory — * `` (EntAssetManufacturingExecutionBackoffice_BPSuppressions.xml) and * `` (BusinessIntelligence_BPSuppressions.xml) — so both are * expanded here. The second used to fall through to the generic "insert before * " branch, which placed the block on the same line as the opening tag. * * A document with NO at all comes back as 'no-items' rather than as a * successful insert: both replaces below are no-ops there, and returning * 'added' with an unchanged document is a ✅ over a file that gained nothing. */ export declare function addDiagnosticSuppression(xml: string, diagnosticXml: string): AddDiagnosticSuppressionResult; /** * A fresh suppression list with no suppressions — used only when * add-diagnostic-suppression targets a model that has never suppressed * anything before, so {Model}_BPSuppressions.xml does not exist yet. * * Every part of this is measured against the 339 AxIgnoreDiagnosticList files * of a shipped 10.0 PackagesLocalDirectory — including, contrary to what an * earlier version of this docblock claimed was unknowable, the empty case: * * • Root is directly. There is no wrapping * element — that name is only the metadata FOLDER. * • The root carries xmlns:i in 264 of those 339 files, so it is what * Microsoft's current serializer emits (the bare root in the remaining 75 * also loads — both spellings ship — but matching the majority keeps a * tool-written file indistinguishable from a VS-written one). * • is the file's own base name, not the model's: * ER_App_Suite_Int_BPSuppressions.xml in model "Electronic Reporting * Application Suite Integration" carries ER_App_Suite_Int_BPSuppressions. * • An EMPTY list is a real, shipped shape — no disclosure needed, and none * is made any more: * EntAssetManufacturingExecutionBackoffice_BPSuppressions.xml → * BusinessIntelligence_BPSuppressions.xml → */ export declare function emptySuppressionListXml(name: string): string; /** * dynamics:// path segments an object of `objectType` can be addressed by. * * The segment is the AOT element type without its 'Ax' prefix — the rule * pathSegmentFor (bpMonikers/index.ts) applies on the ADD side, verified there * against every real entry carrying both and . Deriving it * from the metadata FOLDER instead, as this cleanup first did, agrees for most * types but is measurably wrong for two, and a wrong segment matches nothing: * * • edt → folder AxEdt gives 'Edt', which appears in ZERO real paths. Real * ones name the concrete EDT type: EdtString (62 entries), EdtInt (7), * EdtEnum (4), EdtInt64 (3), EdtDate (2), EdtReal (1), EdtGuid (1). * • query → folder AxQuery gives 'Query'; real paths say QuerySimple (9). * * Deleting an EDT or a query therefore left every one of its suppressions * behind while reporting a clean delete — the exact stale-suppression state * this cleanup exists to prevent. Returning SEVERAL candidate segments is what * covers the EDT family; a prefix is anchored on the object's own name, so an * extra candidate that never occurs simply matches nothing. */ export declare function suppressionPathSegmentsForObjectType(objectType: string, axFolder: string): string[]; /** * Bulk-remove every whose is exactly one of `prefixes` or * addresses a sub-element of one (`{prefix}/…` or `{prefix}?…` — both separators * occur in real files: `dynamics://Form/X/FormDesign/…` and * `dynamics://EdtString/X?StringSize`). Used to clean up suppressions left * behind when the object they targeted is deleted outright — see * deleteD365File.ts. Unlike removeDiagnosticSuppression this never refuses: a * deleted object can legitimately have accumulated several suppressions (a * control, a field, the object itself), and all of them are equally stale once * the object is gone. * * Returns an empty `removed` array (never `null`/throws) when nothing matches or * the file is not a suppression list, so callers can treat this as a * best-effort step that never blocks the delete it follows. */ export declare function removeDiagnosticSuppressionsByPathPrefix(xml: string, prefix: string | string[]): { xml: string; removed: DiagnosticSuppressionEntry[]; }; //# sourceMappingURL=ignoreDiagnosticListXml.d.ts.map