mirror of
https://github.com/olehomelchenko/astrolabe.git
synced 2026-08-08 02:02:33 +00:00
Editor: view-scoped data context — per-view dataset columns in hints and transforms
This commit is contained in:
@@ -75,9 +75,9 @@ This is the at-a-glance list; keep it in sync with them.
|
||||
**Next (flagged for build):**
|
||||
|
||||
- **Multi-view data model** ([`multi-view-data-model-scope.md`](exploration/multi-view-data-model-scope.md)) —
|
||||
durable composition support across the data-facing features. M1 (Vega-Lite-fidelity
|
||||
reference classifier, `core/spec-data`) is done; M2–M4 extend the editor data context,
|
||||
Extract, and the data inspector to be view-scoped.
|
||||
durable composition support across the data-facing features. Done: the Vega-Lite-fidelity
|
||||
reference classifier (`core/spec-data`) and the view-scoped editor data context. Remaining:
|
||||
per-view data inspection (`DataInspector` view selector), then view-scoped Extract.
|
||||
- **Chart Builder · 3B starter examples** ([`chart-builder-enhancement-scope.md`](exploration/chart-builder-enhancement-scope.md) §3) —
|
||||
a small set of curated starters, one per covered FT intent. Reshaped by 3C: a
|
||||
builder-openable starter must reference a dataset, so it ships paired sample datasets (or is
|
||||
|
||||
@@ -286,16 +286,22 @@ thin app-layer services.
|
||||
|
||||
- `spec-transforms` — wrap a view in `layer`/`hconcat`/`vconcat`/`facet`/`repeat`; collapse
|
||||
a single-child composition (`unwrapSingleton`). Object-in/object-out.
|
||||
- `spec-cursor` — `findViewRange` (cursor offset → the enclosing view's byte range) and
|
||||
`valueKeyAtOffset`/`stringValueAtOffset` (the JSON context at the cursor), over `jsonc-parser`.
|
||||
- `spec-fields` — field names a spec's own transforms introduce (their `as`).
|
||||
- `spec-inline-data` — the inline rows a spec carries (`data.values`, a `datasets` entry).
|
||||
- `spec-data` — the Vega-Lite data model: classify a `data` block (`classifyData`, mirroring
|
||||
`isNamedData`), the library reference name (`libraryRefName`), and the data binding in scope
|
||||
at a cursor path (`dataBindingAtPath`, honoring a view's data inheritance from its parent).
|
||||
- `spec-cursor` — `findViewRange` (cursor offset → the enclosing view's byte range),
|
||||
`pathAtOffset` (cursor → JSON path), and `valueKeyAtOffset`/`stringValueAtOffset` (the JSON
|
||||
context at the cursor), over `jsonc-parser`.
|
||||
- `spec-fields` — field names a spec's transforms introduce (their `as`), scoped to a
|
||||
cursor's ancestor chain (`derivedFieldNamesAtPath`).
|
||||
- `spec-inline-data` — the rows a specific `data` binding carries for profiling
|
||||
(`rowsForDataBinding`: inline `values`, or a self-defined `datasets` entry).
|
||||
- `spec-insert` — composition arrays + appending a view to one.
|
||||
|
||||
**Services (app, store-aware via `getState`):** `spec-transform-actions` (the
|
||||
wrap/simplify/add-view operations and their surfaces), `spec-dataset-hints` (completion,
|
||||
hover, inlay providers), `active-dataset` (`dataInfo()` — the columns/types/stats + derived
|
||||
fields the draft sees). `SpecEditor` does the wiring.
|
||||
hover, inlay providers), `active-dataset` (`dataInfoAt(text, offset)` — the columns/types/stats
|
||||
plus derived fields the draft sees at the cursor). `SpecEditor` does the wiring.
|
||||
|
||||
Decision rules:
|
||||
|
||||
@@ -312,12 +318,17 @@ Decision rules:
|
||||
- **One edit path.** The lightbulb returns a `WorkspaceEdit` (no editor handle); the toolbar
|
||||
and palette use `executeEdits`. Both build the replacement through the same
|
||||
serialize-and-reindent step, bracketed by `pushUndoStop`, so ⌘Z restores the prior text.
|
||||
- **Field source for hints.** `dataInfo()` reads columns from the named library dataset the
|
||||
draft references, else profiles the spec's **inline data on the fly** (`spec-inline-data` +
|
||||
`core/profile`) — a "ghost dataset" with nothing stored — and adds the spec's derived
|
||||
fields. Memoized by draft text, since providers fire per keystroke and per scroll. Out of
|
||||
scope: data-dependent derived columns (`pivot`/`lookup` output) and `url`/CSV-string inline
|
||||
data, which need the pipeline run or format-aware parsing.
|
||||
- **Field source for hints (view-scoped).** `dataInfoAt(text, offset)` resolves the data
|
||||
binding of the cursor's **nearest enclosing view** (`dataBindingAtPath` — a child inherits a
|
||||
parent's data unless it declares its own), then its columns: a named **library dataset**
|
||||
(matched case-insensitively, like the renderer), else the binding's **inline rows** profiled
|
||||
on the fly (`rowsForDataBinding` + `core/profile`) — a "ghost dataset" with nothing stored.
|
||||
Derived fields come from that view's and its ancestors' transforms only
|
||||
(`derivedFieldNamesAtPath`), so a sibling view's `calculate` does not leak in. Profiling is
|
||||
memoized per (draft text, enclosing view), so the inlay provider's many per-line queries
|
||||
profile once. A composed spec whose views bind different datasets therefore gets the right
|
||||
columns per view. Out of scope: data-dependent derived columns (`pivot`/`lookup` output) and
|
||||
`url`/CSV-string inline data, which need the pipeline run or format-aware parsing.
|
||||
- **No unknown-field diagnostic.** Hints are additive and forgiving, so over- or
|
||||
under-listing costs nothing; a "field not in data" squiggle would false-positive on every
|
||||
derived or data-dependent field, so there is deliberately none.
|
||||
|
||||
@@ -66,18 +66,21 @@ collection (`spec-fields`), config baking (`spec-config`), standalone export
|
||||
|
||||
- **M1 — data-model foundation** ✅ — `core/spec-data` classifier mirroring
|
||||
`isNamedData`; `spec-refs` + `rendering` routed through it. Closes clash 1.
|
||||
- **M2 — view-scoped editor context** — pure `dataContextAtPath(spec, path)`:
|
||||
climb the cursor's JSON path to the nearest enclosing `data` (honoring
|
||||
Vega-Lite's parent→child data inheritance), classify it, and collect
|
||||
ancestor-chain derived fields. Rework `active-dataset` to be cursor-scoped and
|
||||
thread the offset through the three Monaco providers and the facet/repeat
|
||||
defaults. Resolve columns for every form: library ref, inline `values`,
|
||||
named-inline, self-defined `datasets`, url (no static rows), generator (none).
|
||||
- **M2 — view-scoped editor context** ✅ — `dataBindingAtPath` (climb the cursor's
|
||||
JSON path to the nearest enclosing `data`, honoring Vega-Lite's parent→child
|
||||
inheritance) + `derivedFieldNamesAtPath` (ancestor-chain `as` outputs).
|
||||
`active-dataset` is cursor-scoped (`dataInfoAt(text, offset)`), resolving columns
|
||||
for every form (library ref case-insensitive, inline, named-inline, self-defined
|
||||
`datasets`, url/generator → none); the three Monaco providers and the
|
||||
facet/repeat defaults pass the cursor offset.
|
||||
- **M4 — multi-view inspection** (pulled ahead of M3) — group the dataflow's
|
||||
datasets into per-view input/resolved pairs (`result-data`) and add a view
|
||||
selector to `DataInspector` (new interactive widget → `/council`). The data
|
||||
inspector executes the live pipeline, so it is the place to review post-transform
|
||||
rows (melt/fold/pivot/aggregate); today it surfaces one heuristic input/resolved
|
||||
pair across the whole composition, with no per-view choice.
|
||||
- **M3 — view-scoped extract** — seed Extract from the focused view's inline data
|
||||
(reusing the cursor-scope machinery) and rewrite that view's `data`.
|
||||
- **M4 — multi-view inspection** — group the dataflow's datasets into per-view
|
||||
input/resolved pairs (`result-data`) and add a view selector to `DataInspector`
|
||||
(new interactive widget → `/council`).
|
||||
|
||||
Delivery is incremental, one milestone per commit, verified against real behavior.
|
||||
The consolidated data-model contract write-up into `docs/architecture` (05/08)
|
||||
|
||||
Reference in New Issue
Block a user