mirror of
https://github.com/olehomelchenko/astrolabe.git
synced 2026-08-08 10:12:34 +00:00
Fix dataset-ref walk false positive and wire spec-mandated success toasts
- Prune the data payload and top-level datasets keys in all three ref walks (extractDatasetRefs, renameDatasetInSpec, resolveDatasetRefs) so a data row carrying a field named "data" is no longer misread as a library reference, spuriously rewritten, or made to throw DatasetNotFoundError. Adds tests, including a guard that lookup-transform refs (from.data) still resolve. - Wire the deferred success toasts now the Toaster has landed: publish, revert, extract-to-dataset, and snippet/dataset delete. Copy follows the council title-vs-message rule (title states the action, message adds the consequence). - Reconcile the spec's blanket toast mandate to "toast only what the user can't already see": no toast on visible-result creates (snippet, dataset form); Copy Reference stays inline and gains an aria-live announcement (new shared .visually-hidden utility) instead of a toast-per-copy. - Move the toast region to bottom-right so it stops covering the header action cluster (Publish/Revert, theme/datasets). - Update docs/spec 01F/02/05 and docs/architecture/07 + 10 to match.
This commit is contained in:
+16
-14
@@ -149,11 +149,12 @@ function resolvedData(dataset: ResolvableDataset, rest: SpecNode): SpecNode {
|
||||
|
||||
/**
|
||||
* Replace every named-data reference in `node` with its library dataset's
|
||||
* contents, recursing through the entire spec (arrays and objects) so refs
|
||||
* anywhere are resolved — matching `extractDatasetRefs`. A self-defined name is
|
||||
* left untouched; an unknown library name throws `DatasetNotFoundError`. Matching
|
||||
* is case-insensitive, mirroring naming.ts. Mutates in place; the caller already
|
||||
* works on a copy.
|
||||
* contents, recursing through the spec (arrays and objects) so refs anywhere are
|
||||
* resolved — matching `extractDatasetRefs`, including pruning the `data` and
|
||||
* top-level `datasets` payload keys so resolution never descends into user data
|
||||
* rows. A self-defined name is left untouched; an unknown library name throws
|
||||
* `DatasetNotFoundError`. Matching is case-insensitive, mirroring naming.ts.
|
||||
* Mutates in place; the caller already works on a copy.
|
||||
*/
|
||||
function resolveDatasetRefs(
|
||||
node: unknown,
|
||||
@@ -177,15 +178,16 @@ function resolveDatasetRefs(
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: this walks EVERY key, so it also descends into inlined data payloads
|
||||
// (the just-resolved `values`, a spec's `datasets`/`data.values`). That's
|
||||
// wasteful for large inline data on every debounced render, and a row with a
|
||||
// field literally named `data` holding `{ name: "x" }` would be spuriously
|
||||
// resolved or throw DatasetNotFoundError. extractDatasetRefs shares this broad
|
||||
// walk. A scoped walk (recurse only into the known sub-spec/container keys +
|
||||
// `transform[].lookup.from`, never into data payloads) would be safer and
|
||||
// faster — change deliberately, with tests for where refs may legally appear.
|
||||
for (const key of Object.keys(node)) resolveDatasetRefs(node[key], byName, selfDefined);
|
||||
// Recurse into every key except the two that hold data payloads (`data` —
|
||||
// resolved/captured above; `datasets` — the spec's own inline data). Pruning
|
||||
// them avoids descending into the just-resolved `values` and into user data
|
||||
// rows, where a field named `data` holding `{ name: "x" }` would otherwise be
|
||||
// spuriously resolved or throw DatasetNotFoundError. extractDatasetRefs prunes
|
||||
// the same two keys so resolution and extraction stay in agreement.
|
||||
for (const key of Object.keys(node)) {
|
||||
if (key === 'data' || key === 'datasets') continue;
|
||||
resolveDatasetRefs(node[key], byName, selfDefined);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user