/** * Model descriptor reader — `//Descriptor/.xml`. * * `` is the only statement of what a model may see: xppc * resolves types against the referenced packages, not against everything * installed, so an indexed type can still be invisible to the model being * compiled. The visible set is the model's own package plus its DIRECT * references — walking the closure would mark such a type visible again and * hide the defect this exists to catch. * * Not a compiler: a table in a referenced package can still need a further * reference because a third package contributes a table extension to it. */ /** * Extract every `` entry of a descriptor's ``. * * Scoped to that ELEMENT, not scanned flat over the document. The flat scan this * replaces reasoned only about `` — `i:nil` in every descriptor * observed on a real box, so it contributes nothing — and missed the OTHER * `` arrays a descriptor carries: `` and * ``. Both are ordinary string lists, and `` * sorts BEFORE `` in the serialized document, so its entries * came back as module references. * * Measured on a 10.0.2527 PackagesLocalDirectory plus the custom roots beside * it: 112 of 176 descriptors over-reported, 606 phantom references in total. * `Foundation.xml` answered 157 for a model that references 46; * `ApplicationPlatform.xml` answered 19 for a model that references NONE. * * That is not cosmetic. Its reader treats the result as the set of packages a * model may see: getModelVisibility turns it into `visiblePackages`, the oracle * resolve_references uses to decide an indexed type is invisible to the model * being compiled. Every phantom entry made that oracle MORE permissive, so the * missing-reference defect it exists to catch was silently waved through — * which is the exact compile-time `classStr`/type failure this module's own * header describes. * * Returns [] for a nil or absent element: a model that references nothing. An * unreadable descriptor is the caller's to report (getModelVisibility answers * null), never an empty list. */ export declare function parseModuleReferences(descriptorXml: string): string[]; /** The PackagesLocalDirectory root contained in a package or workspace path. */ export declare function packagesRootFromPath(candidate: string | undefined | null): string | null; export interface ModelVisibility { /** Target model, for diagnostics. */ model: string; /** PackagesLocalDirectory root the indexed file paths are relative to. */ packagesRoot: string; /** Lower-cased package folder names the model may reference (incl. its own). */ visiblePackages: ReadonlySet; /** * Package folder owning an indexed file, or null when the path is not under * this packages root. Null means "cannot tell" and must silence the check. */ packageOf(filePath: string): string | null; } /** * Build (and memoise) the visibility oracle for `modelName`; null whenever the * answer would be a guess. Callers must then skip the check — a missing * descriptor turning into a wall of errors is worse than the gap it closes. */ export declare function getModelVisibility(packagesRoot: string | null | undefined, modelName: string | null | undefined): ModelVisibility | null; /** * Drop the memoised visibility of `modelName` under every root. * * The descriptor writers call this after every successful write. Without it the * oracle keeps the reference set the model had when it was first asked, so * resolve_references goes on reporting `not-visible-from-model` — and telling * the agent to add the very reference it has just added — until the server * restarts; a remove leaves it too permissive the same way. */ export declare function invalidateModelVisibility(modelName: string): void; /** Uncached form — exported for tests, which need a fresh fixture each time. */ export declare function buildModelVisibility(packagesRoot: string | null | undefined, modelName: string | null | undefined): ModelVisibility | null; export type AddModuleReferenceResult = /** Added. `xml` is the updated document. */ { kind: 'added'; xml: string; } /** Already referenced — refuse rather than write a second ``. */ | { kind: 'duplicate'; existing: string; } /** No `` element at all; the caller declines rather than inventing one. */ | { kind: 'no-element'; } /** Not a package folder name — see isValidModuleReferenceName. */ | { kind: 'invalid-name'; }; export type RemoveModuleReferenceResult = /** Removed. `xml` is the updated document, `removed` the entry as it was spelled. */ { kind: 'removed'; xml: string; removed: string; } /** Not referenced. `present` is what IS referenced, for the message. */ | { kind: 'not-found'; present: string[]; } /** No `` element at all. */ | { kind: 'no-element'; }; /** * Could `name` be a package folder name? * * Checked before anything is written, because the entry is interpolated into * `…` verbatim: whitespace inside the name writes an * entry parseModuleReferences cannot read back (so it is neither a detected * duplicate nor removable), an all-blank name writes an empty entry, and `&`/`<` * write a malformed descriptor. Package folders on a real install use letters, * digits and `_`, plus `-` in custom ones (`fm-mcp`); `.` is admitted for * dotted ISV names, but never leading, so the name cannot step out of a * packages root when probed as a folder. */ export declare function isValidModuleReferenceName(name: string): boolean; /** * Add one `` entry to ``. * * Idempotent by refusal, matching add-diagnostic-suppression: a duplicate comes * back as 'duplicate' rather than as a silent no-op, because a caller who does * not know the reference is already there learns more from being told than from * a ✅ over an unchanged file. Comparison is case-insensitive — a package folder * name is, and two entries differing only in case are one reference to xppc and * two lines to a reviewer. * * Placement follows the file's OWN convention, the same way the indentation * does. A descriptor that is already sorted gets the entry in sorted position; * one that is not gets it appended. * * An earlier version of this docblock asserted that no shipped descriptor is * sorted and always appended. That was wrong, and measurably so: across the 176 * descriptors of a 10.0.2527 PackagesLocalDirectory plus the custom and ISV * roots beside it, 137 of the 173 with two or more references are in ascending * case-insensitive order, and every custom model on the box was among them — * i.e. the sorted convention is the one the files a write actually targets keep. * Appending to a sorted list puts the new entry out of order, which is a line a * reviewer stops at and which the next Visual Studio save silently re-sorts, * turning one intended change into two diffs. * * The 36 unsorted ones (Foundation, SCMControls, several *Integration models) * are left alone rather than tidied: re-sorting a file to add one line to it is * the larger diff, not the smaller one. */ export declare function addModuleReference(xml: string, moduleName: string): AddModuleReferenceResult; /** * Remove one `` entry from ``, matched * case-insensitively on its text. * * Removing the LAST entry collapses the element to ``, * keeping its attributes — the shape a shipped descriptor with no references * actually has, and the one that makes add-then-remove a byte-identical round * trip on a file that started empty. (The one nuance: a list that started * `i:nil="true"` comes back as the self-closing form WITHOUT the nil, because * adding a reference is what dropped it. "No list" and "empty list" both mean * the model references nothing, so nothing is lost.) */ export declare function removeModuleReference(xml: string, moduleName: string): RemoveModuleReferenceResult; /** * Where a model's descriptor actually is under `packagesRoot`, or null when it * is not there — the write side's equivalent of buildModelVisibility, which * collapses "no such file" into the same null as "unreadable". * * Reuses findDescriptor's probe order (package == model first, then a bounded * sweep for an ISV model inside a differently-named package) so a write lands on * the file the readers read. */ export declare function findDescriptorPath(packagesRoot: string, modelName: string): { filePath: string; packageName: string; } | null; //# sourceMappingURL=modelDescriptor.d.ts.map