@zwishing/emap 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (114) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/LICENSE +373 -0
  3. package/README.md +294 -0
  4. package/SECURITY.md +56 -0
  5. package/dist/adapter/mapshaper-adapter.d.ts +282 -0
  6. package/dist/core/drag-pan-handler.d.ts +28 -0
  7. package/dist/core/events.d.ts +16 -0
  8. package/dist/core/interactions.d.ts +20 -0
  9. package/dist/core/mapshaper-worker-pool.d.ts +151 -0
  10. package/dist/core/tween.d.ts +26 -0
  11. package/dist/edit/commands/composite.d.ts +16 -0
  12. package/dist/edit/commands/dataset-replace.d.ts +43 -0
  13. package/dist/edit/commands/feature-affine.d.ts +72 -0
  14. package/dist/edit/commands/feature-create.d.ts +47 -0
  15. package/dist/edit/commands/feature-delete.d.ts +72 -0
  16. package/dist/edit/commands/feature-property-change.d.ts +34 -0
  17. package/dist/edit/commands/feature-translate.d.ts +55 -0
  18. package/dist/edit/commands/field-add.d.ts +24 -0
  19. package/dist/edit/commands/field-remove.d.ts +20 -0
  20. package/dist/edit/commands/field-rename.d.ts +19 -0
  21. package/dist/edit/commands/split-shared-arcs.d.ts +71 -0
  22. package/dist/edit/commands/vertex-delete.d.ts +26 -0
  23. package/dist/edit/commands/vertex-insert.d.ts +26 -0
  24. package/dist/edit/commands/vertex-move.d.ts +45 -0
  25. package/dist/edit/edit-command.d.ts +72 -0
  26. package/dist/edit/edit-history.d.ts +130 -0
  27. package/dist/edit/transaction.d.ts +59 -0
  28. package/dist/emap-worker.js +1 -0
  29. package/dist/emap.css +157 -0
  30. package/dist/emap.js +5 -0
  31. package/dist/emap.mjs +5 -0
  32. package/dist/geo/bounds.d.ts +18 -0
  33. package/dist/geo/crs-resolver.d.ts +35 -0
  34. package/dist/geo/projection.d.ts +28 -0
  35. package/dist/geo/transform.d.ts +19 -0
  36. package/dist/geo/viewport.d.ts +52 -0
  37. package/dist/index.d.ts +86 -0
  38. package/dist/map/attribute-ops.d.ts +61 -0
  39. package/dist/map/command-args.d.ts +28 -0
  40. package/dist/map/edit-sessions.d.ts +97 -0
  41. package/dist/map/edit-state-store.d.ts +41 -0
  42. package/dist/map/emap-host.d.ts +79 -0
  43. package/dist/map/feature-accessor.d.ts +43 -0
  44. package/dist/map/feature-query.d.ts +58 -0
  45. package/dist/map/highlight-manager.d.ts +17 -0
  46. package/dist/map/layer-registry.d.ts +33 -0
  47. package/dist/map/layer.d.ts +29 -0
  48. package/dist/map/map.d.ts +386 -0
  49. package/dist/map/mapshaper-ops.d.ts +56 -0
  50. package/dist/map/op-result.d.ts +46 -0
  51. package/dist/map/ops/_context.d.ts +41 -0
  52. package/dist/map/ops/_runner.d.ts +55 -0
  53. package/dist/map/ops/affine.d.ts +4 -0
  54. package/dist/map/ops/buffer.d.ts +4 -0
  55. package/dist/map/ops/check-geometry.d.ts +4 -0
  56. package/dist/map/ops/clean.d.ts +4 -0
  57. package/dist/map/ops/clip-erase.d.ts +5 -0
  58. package/dist/map/ops/data-fill.d.ts +4 -0
  59. package/dist/map/ops/dissolve.d.ts +20 -0
  60. package/dist/map/ops/divide.d.ts +4 -0
  61. package/dist/map/ops/drop-layer.d.ts +4 -0
  62. package/dist/map/ops/each-filter.d.ts +5 -0
  63. package/dist/map/ops/explode.d.ts +4 -0
  64. package/dist/map/ops/filter-fields.d.ts +4 -0
  65. package/dist/map/ops/filter-geom.d.ts +4 -0
  66. package/dist/map/ops/filter-islands.d.ts +4 -0
  67. package/dist/map/ops/filter-slivers.d.ts +4 -0
  68. package/dist/map/ops/innerlines.d.ts +4 -0
  69. package/dist/map/ops/intersection-points.d.ts +4 -0
  70. package/dist/map/ops/join-table.d.ts +4 -0
  71. package/dist/map/ops/lines.d.ts +4 -0
  72. package/dist/map/ops/merge-layers.d.ts +4 -0
  73. package/dist/map/ops/mosaic.d.ts +4 -0
  74. package/dist/map/ops/points.d.ts +4 -0
  75. package/dist/map/ops/polygons.d.ts +4 -0
  76. package/dist/map/ops/project.d.ts +4 -0
  77. package/dist/map/ops/rebuild-topology.d.ts +4 -0
  78. package/dist/map/ops/rename-fields.d.ts +4 -0
  79. package/dist/map/ops/rename-layer.d.ts +4 -0
  80. package/dist/map/ops/simplify.d.ts +4 -0
  81. package/dist/map/ops/snap.d.ts +4 -0
  82. package/dist/map/ops/sort-features.d.ts +4 -0
  83. package/dist/map/ops/split-layer.d.ts +4 -0
  84. package/dist/map/ops/union.d.ts +4 -0
  85. package/dist/map/ops/unique-features.d.ts +4 -0
  86. package/dist/map/selection.d.ts +73 -0
  87. package/dist/map/types.d.ts +1072 -0
  88. package/dist/map/worker-routing.d.ts +40 -0
  89. package/dist/mapshaper-vendor.js +1 -0
  90. package/dist/renderer/canvas-painter.d.ts +50 -0
  91. package/dist/renderer/edit-overlay-renderer.d.ts +22 -0
  92. package/dist/renderer/painter.d.ts +52 -0
  93. package/dist/shim.d.ts +1 -0
  94. package/dist/source/display-arcs.d.ts +49 -0
  95. package/dist/source/layer-utils.d.ts +12 -0
  96. package/dist/source/mapshaper-runner.d.ts +22 -0
  97. package/dist/source/source.d.ts +80 -0
  98. package/dist/source/topology-source.d.ts +145 -0
  99. package/dist/types/mapshaper-types.d.ts +182 -0
  100. package/dist/ui/basemap-control.d.ts +35 -0
  101. package/dist/ui/box-select-control.d.ts +67 -0
  102. package/dist/ui/control.d.ts +6 -0
  103. package/dist/ui/draw-feature-control.d.ts +82 -0
  104. package/dist/ui/edit-toolbar.d.ts +27 -0
  105. package/dist/ui/history-control.d.ts +29 -0
  106. package/dist/ui/lasso-select-control.d.ts +96 -0
  107. package/dist/ui/navigation-control.d.ts +16 -0
  108. package/dist/ui/simplify-control.d.ts +40 -0
  109. package/dist/ui/status-control.d.ts +23 -0
  110. package/dist/ui/vertex-edit-control.d.ts +111 -0
  111. package/dist/validation/builtin/topology.d.ts +19 -0
  112. package/dist/validation/registry.d.ts +23 -0
  113. package/dist/validation/validator.d.ts +47 -0
  114. package/package.json +90 -0
@@ -0,0 +1,71 @@
1
+ import type { EditCommand } from '../edit-command';
2
+ import { type MapshaperLayer, type PathShape } from '../../types/mapshaper-types';
3
+ import type { TopologySource } from '../../source/source';
4
+ /**
5
+ * One feature whose shape was rewritten to point at duplicated arc ids.
6
+ * Captured at command-construction time so undo restores it exactly.
7
+ */
8
+ export interface SplitSharedArcsRemap {
9
+ layer: MapshaperLayer;
10
+ featureId: number;
11
+ /** Snapshot of `layer.shapes[featureId]` BEFORE the split (deep cloned). */
12
+ originalShape: PathShape;
13
+ /** The post-split shape that uses the new arc ids. */
14
+ newShape: PathShape;
15
+ }
16
+ /**
17
+ * Vertex data for a single arc to be appended onto the source's `ArcCollection`.
18
+ * Slices of the original arc's xx/yy (and zz when simplification is in play).
19
+ */
20
+ export interface AppendedArc {
21
+ xx: Float64Array;
22
+ yy: Float64Array;
23
+ zz?: Float64Array | null;
24
+ }
25
+ export interface SplitSharedArcsCommandOptions {
26
+ source: TopologySource;
27
+ /** Pre-computed shape rewrites — one entry per affected feature. */
28
+ remaps: SplitSharedArcsRemap[];
29
+ /**
30
+ * Vertex data for every arc to append, in the order the new arc ids were
31
+ * assigned (first appended arc id = `originalArcCount`, second = +1, …).
32
+ */
33
+ appendedArcs: AppendedArc[];
34
+ /** Arc count BEFORE the split. Used by undo to truncate. */
35
+ originalArcCount: number;
36
+ }
37
+ /**
38
+ * Duplicate "shared" arcs (arcs referenced by both selected and unselected
39
+ * features) so a subsequent translate / rotate / scale on the selection no
40
+ * longer drags unselected neighbours along by their shared boundary.
41
+ *
42
+ * Topology stays valid: unselected features keep their original arc ids,
43
+ * selected features get rewritten to point at the duplicates.
44
+ *
45
+ * Undo restores every rewritten shape to its captured pre-split state and
46
+ * truncates the appended arcs off the `ArcCollection`. Redo re-appends and
47
+ * re-rewrites. Both directions go through `arcs.updateVertexData` so the
48
+ * collection's bounds and indices stay coherent.
49
+ */
50
+ export declare class SplitSharedArcsCommand implements EditCommand {
51
+ private readonly opts;
52
+ readonly label: string;
53
+ constructor(opts: SplitSharedArcsCommandOptions);
54
+ do(): void;
55
+ undo(): void;
56
+ }
57
+ /**
58
+ * Walks the dataset's path-feature shapes once, finds arcs referenced by
59
+ * BOTH selected and unselected features, and returns the data needed to
60
+ * construct a {@link SplitSharedArcsCommand}. Returns `null` (no command
61
+ * needed) when the selection has no boundary shared with anything outside.
62
+ *
63
+ * `selected` lists `(layer, featureId)` pairs in the active selection; the
64
+ * caller is responsible for restricting these to one source. `allLayers`
65
+ * is the full layer list of that source so we can find unselected
66
+ * references.
67
+ */
68
+ export declare function planSharedArcSplit(source: TopologySource, selected: Array<{
69
+ layer: MapshaperLayer;
70
+ featureId: number;
71
+ }>, allLayers: MapshaperLayer[]): SplitSharedArcsCommandOptions | null;
@@ -0,0 +1,26 @@
1
+ import type { EditCommand } from '../edit-command';
2
+ import { type ArcCollection } from '../../types/mapshaper-types';
3
+ import type { TopologySource } from '../../source/source';
4
+ import { type MapshaperAdapter } from '../../adapter/mapshaper-adapter';
5
+ export interface VertexDeleteCommandOptions {
6
+ /** Global vertex index of the deleted vertex (recorded before deletion). */
7
+ vertexIndex: number;
8
+ /** Coordinate of the deleted vertex (recorded before deletion). */
9
+ coords: [number, number];
10
+ arcs: ArcCollection;
11
+ source: TopologySource;
12
+ /** Adapter override for tests; defaults to the process-wide singleton. */
13
+ adapter?: MapshaperAdapter;
14
+ }
15
+ /**
16
+ * Reverse a vertex deletion by re-inserting at the same global index. Pair
17
+ * with `VertexInsertCommand`'s symmetry: this command's `do()` performs the
18
+ * deletion (called only on redo), `undo()` restores the vertex.
19
+ */
20
+ export declare class VertexDeleteCommand implements EditCommand {
21
+ private readonly opts;
22
+ readonly label = "Delete vertex";
23
+ constructor(opts: VertexDeleteCommandOptions);
24
+ do(): void;
25
+ undo(): void;
26
+ }
@@ -0,0 +1,26 @@
1
+ import type { EditCommand } from '../edit-command';
2
+ import { type ArcCollection } from '../../types/mapshaper-types';
3
+ import type { TopologySource } from '../../source/source';
4
+ import { type MapshaperAdapter } from '../../adapter/mapshaper-adapter';
5
+ export interface VertexInsertCommandOptions {
6
+ /** Global vertex index where the new vertex was inserted. */
7
+ insertionId: number;
8
+ /** Coordinate of the inserted vertex. */
9
+ point: [number, number];
10
+ arcs: ArcCollection;
11
+ source: TopologySource;
12
+ /** Adapter override for tests; defaults to the process-wide singleton. */
13
+ adapter?: MapshaperAdapter;
14
+ }
15
+ /**
16
+ * Reverse a vertex insertion by deleting at the same global index.
17
+ * mapshaper's deleteVertex shifts subsequent indices back into place via
18
+ * updateVertexData, which also rebuilds arc bounds.
19
+ */
20
+ export declare class VertexInsertCommand implements EditCommand {
21
+ private readonly opts;
22
+ readonly label = "Insert vertex";
23
+ constructor(opts: VertexInsertCommandOptions);
24
+ do(): void;
25
+ undo(): void;
26
+ }
@@ -0,0 +1,45 @@
1
+ import type { EditCommand } from '../edit-command';
2
+ import { type ArcCollection } from '../../types/mapshaper-types';
3
+ import type { TopologySource } from '../../source/source';
4
+ import { type MapshaperAdapter } from '../../adapter/mapshaper-adapter';
5
+ export interface VertexMoveCommandOptions {
6
+ /**
7
+ * IDs of every vertex at the moved topological node. mapshaper's
8
+ * snapVerticesToPoint moves them all in lock-step, preserving topology.
9
+ */
10
+ vertexIds: number[];
11
+ /** Original coordinate of the topological node before the drag. */
12
+ from: [number, number];
13
+ /** Final coordinate after the drag. */
14
+ to: [number, number];
15
+ arcs: ArcCollection;
16
+ source: TopologySource;
17
+ /** Adapter override for tests; defaults to the process-wide singleton. */
18
+ adapter?: MapshaperAdapter;
19
+ }
20
+ /**
21
+ * Reverse a vertex drag (including topologically shared vertices) by
22
+ * re-running mapshaper's snapVertices with the captured `from` /
23
+ * `to` coordinates. The function updates each affected arc's bounds
24
+ * internally, so no extra bookkeeping is required.
25
+ *
26
+ * Mergeable: consecutive moves of the SAME topological node within
27
+ * {@link MERGE_WINDOW_MS} collapse into one undo entry. The merged
28
+ * command keeps the original `from` (the very first pre-drag snapshot)
29
+ * and adopts the latest `to`, so a single undo reverses an entire
30
+ * arrow-key nudge sequence.
31
+ */
32
+ export declare class VertexMoveCommand implements EditCommand {
33
+ private readonly opts;
34
+ readonly label = "Move vertex";
35
+ /**
36
+ * Wall-clock at construction time; refreshed by `merge()`. Used by
37
+ * `mergeable()` to bound coalescence to a short interactive window.
38
+ */
39
+ private _mergeAt;
40
+ constructor(opts: VertexMoveCommandOptions);
41
+ do(): void;
42
+ undo(): void;
43
+ mergeable(prev: EditCommand): boolean;
44
+ merge(next: EditCommand): void;
45
+ }
@@ -0,0 +1,72 @@
1
+ /**
2
+ * An undoable edit memento. NOT to be confused with a mapshaper
3
+ * "operation" (`emap.ops.*`) — those wrap a CLI / parsed-command run
4
+ * against a dataset and internally push a `DatasetReplaceCommand` to
5
+ * history. `EditCommand` is the lower-level abstraction that lives on
6
+ * the undo / redo stack.
7
+ *
8
+ * Lifecycle (memento pattern):
9
+ * - The caller mutates the data, then constructs the command and calls
10
+ * `Emap.pushCommand(cmd)`. The command stores any state needed to
11
+ * reverse the change. `pushCommand` does NOT call `do()`.
12
+ * - On undo, `EditHistory` invokes `cmd.undo()` to restore the prior state.
13
+ * - On redo, `EditHistory` invokes `cmd.do()` to re-apply the change.
14
+ *
15
+ * Implementations must capture enough state in their constructor that
16
+ * both `do()` and `undo()` can run multiple times without diverging.
17
+ */
18
+ export interface EditCommand {
19
+ /** Re-apply the operation. Called by `EditHistory.redo()`. */
20
+ do(): void;
21
+ /** Reverse the operation. Called by `EditHistory.undo()`. */
22
+ undo(): void;
23
+ /** Optional human-readable label, surfaced in `historychange` events. */
24
+ readonly label?: string;
25
+ /**
26
+ * Optional merge predicate, evaluated by `EditHistory.push` against the
27
+ * current top of the undo stack. When `true`, the new command is NOT
28
+ * pushed; instead `prev.merge(this)` is invoked and `prev` absorbs the
29
+ * follow-up's effect. Used to collapse rapid repeated edits — successive
30
+ * arrow-key vertex nudges, mouse-drag tween steps, etc. — into one
31
+ * undoable entry.
32
+ *
33
+ * Implementations should be cheap (O(N) at worst over command-internal
34
+ * fields) and stable (no I/O, no side effects).
35
+ */
36
+ mergeable?(prev: EditCommand): boolean;
37
+ /**
38
+ * Companion to {@link mergeable}: invoked by `EditHistory.push` only
39
+ * when `next.mergeable(this)` returned `true`. Mutates this command in
40
+ * place to absorb `next`'s effect; `next` is discarded after the call
41
+ * returns. Implementations typically refresh a "newest-coordinate"
42
+ * field while preserving the oldest "starting" capture so undo still
43
+ * reverses the cumulative work.
44
+ */
45
+ merge?(next: EditCommand): void;
46
+ /**
47
+ * Static marker: when `true`, pushing this command tells `EditHistory`
48
+ * to flag every command currently in the undo stack as `stale`. Used by
49
+ * `DatasetReplaceCommand` (clip / dissolve / buffer / …) — those swap
50
+ * out the live dataset object, so commands captured against the OLD
51
+ * dataset can no longer mutate the right reference.
52
+ *
53
+ * The command itself is NOT stale at push time; only the entries below
54
+ * it become stale.
55
+ */
56
+ readonly invalidatesPriorCommands?: boolean;
57
+ /**
58
+ * Set by `EditHistory.push` when an `invalidatesPriorCommands` command
59
+ * is pushed above this entry. Stays `true` for the rest of this entry's
60
+ * lifetime — even after the invalidating command is undone, the captured
61
+ * dataset reference is still orphaned (the in-place undo of a
62
+ * dataset-swap restores a deep copy that has a different identity from
63
+ * the object this command was constructed against).
64
+ *
65
+ * `EditHistory.undo` skips stale commands: pops them onto the redo
66
+ * stack without invoking `undo()` and surfaces the skip via the
67
+ * `HistoryStateSnapshot.skippedStale` flag on the next change event.
68
+ * UIs should treat the boundary as a "history barrier" — visible in
69
+ * the list, but un-replayable.
70
+ */
71
+ stale?: boolean;
72
+ }
@@ -0,0 +1,130 @@
1
+ import type { EditCommand } from './edit-command';
2
+ export interface EditHistoryOptions {
3
+ /**
4
+ * Maximum number of commands retained in the undo stack. Older commands
5
+ * are evicted when this is exceeded. Defaults to 200.
6
+ */
7
+ maxSize?: number;
8
+ }
9
+ export interface HistoryStateSnapshot {
10
+ canUndo: boolean;
11
+ canRedo: boolean;
12
+ /** Label of the most recent command at the top of the undo stack, if any. */
13
+ label?: string;
14
+ /**
15
+ * Number of commands currently in the undo stack flagged as
16
+ * `stale`. Non-zero after any `DatasetReplaceCommand` lands; the UI
17
+ * can render a divider in the history list at the boundary.
18
+ */
19
+ staleCount: number;
20
+ /**
21
+ * `true` iff the command that {@link undo} would next visit is stale
22
+ * (i.e. cannot be reversed in place). Provides a single boolean for UI
23
+ * tooltips like "the next undo crosses a topology rebuild — earlier
24
+ * edits cannot be replayed".
25
+ */
26
+ topIsStale: boolean;
27
+ /**
28
+ * `true` only on the {@link HistoryStateSnapshot} produced immediately
29
+ * after `undo()` skipped a stale command. Resets on the next event.
30
+ * Used by UI to surface a one-shot toast.
31
+ */
32
+ skippedStale?: boolean;
33
+ }
34
+ /**
35
+ * Linear undo / redo history.
36
+ *
37
+ * - `push(cmd)` records `cmd` and clears any pending redo entries. It does NOT
38
+ * invoke `cmd.do()` — the caller is expected to have already performed the
39
+ * work; the command captures what was changed so it can be reversed.
40
+ * - `undo()` invokes `cmd.undo()` and moves `cmd` from the undo stack to the
41
+ * redo stack.
42
+ * - `redo()` invokes `cmd.do()` and moves `cmd` back onto the undo stack.
43
+ */
44
+ export declare class EditHistory {
45
+ private _undoStack;
46
+ private _redoStack;
47
+ private _maxSize;
48
+ /**
49
+ * `true` for exactly one snapshot following an `undo()` / `redo()` call
50
+ * that traversed a stale command. Surfaced via `snapshot().skippedStale`
51
+ * so the host can fire one-shot UI feedback. Reset on the next
52
+ * non-stale traversal or on `clear()`.
53
+ */
54
+ private _lastSkippedStale;
55
+ /**
56
+ * Active capture buffer for the {@link beginCapture} protocol used by
57
+ * `Transaction`. While non-null, every `push(cmd)` diverts into this
58
+ * buffer instead of mutating the undo stack. `endCapture()` returns
59
+ * the collected commands and unsets this. Nested captures are not
60
+ * supported — a second `beginCapture()` while one is active throws.
61
+ */
62
+ private _captureBuffer;
63
+ constructor(options?: EditHistoryOptions);
64
+ /**
65
+ * Push a new command, evicting the oldest entry if at capacity.
66
+ *
67
+ * Merge fast-path: if the top of the undo stack defines a `merge`
68
+ * companion AND the incoming command's `mergeable(top)` returns true,
69
+ * the top absorbs the incoming command and nothing is pushed. The
70
+ * redo stack is still cleared (the new edit invalidates forward
71
+ * replay). Used by `VertexMoveCommand` / `FeatureTranslateCommand`
72
+ * to coalesce rapid drag / nudge sequences into one undo step.
73
+ *
74
+ * If `cmd.invalidatesPriorCommands` is `true` (DatasetReplaceCommand),
75
+ * every entry currently in the undo stack is flagged `stale = true`
76
+ * before this command is pushed. The command itself is NOT marked
77
+ * stale — it remains undoable as the boundary itself.
78
+ */
79
+ push(cmd: EditCommand): void;
80
+ /**
81
+ * Begin a transaction-style capture session. While active, `push(cmd)`
82
+ * routes every command into an internal buffer instead of mutating the
83
+ * undo stack, so a multi-step transaction can batch its child commands
84
+ * and present them as a single undo entry on commit.
85
+ *
86
+ * Throws if a capture is already in progress — nested transactions are
87
+ * not supported. Pair with {@link endCapture}; for safety, transaction
88
+ * code should call `endCapture()` from a `finally`-style path so an
89
+ * error in the middle doesn't leave the history stuck in capture mode.
90
+ */
91
+ beginCapture(): void;
92
+ /**
93
+ * End the active capture session and return the collected commands in
94
+ * push order. No-op (returns `[]`) if no capture is active. After this
95
+ * call, subsequent `push()` calls resume normal undo-stack behaviour.
96
+ */
97
+ endCapture(): EditCommand[];
98
+ /** True iff a {@link beginCapture} session is currently active. */
99
+ isCapturing(): boolean;
100
+ /**
101
+ * Pop the top command, invoke its `undo()`, and move it to the redo stack.
102
+ * Returns the executed command, or `null` if there was nothing to undo.
103
+ *
104
+ * **Stale handling**: when the top command's `stale` flag is `true`, the
105
+ * command is moved to the redo stack WITHOUT invoking `undo()` (its
106
+ * captured references point at an object the live dataset no longer
107
+ * uses; running it would write to the wrong place). The skip is
108
+ * reflected in the next {@link snapshot} via `skippedStale: true`.
109
+ * `undo()` still returns the moved command so callers can detect that
110
+ * a step was traversed.
111
+ */
112
+ undo(): EditCommand | null;
113
+ /**
114
+ * Pop the top redo entry, invoke its `do()`, and move it back to the undo
115
+ * stack. Returns the executed command, or `null` if there was nothing.
116
+ *
117
+ * Stale commands on the redo stack get the same skip semantics as
118
+ * `undo()` — the redo is a no-op transition because the captured refs
119
+ * are still orphaned even though the entry is moving forward in time.
120
+ */
121
+ redo(): EditCommand | null;
122
+ /** Empty both stacks. */
123
+ clear(): void;
124
+ canUndo(): boolean;
125
+ canRedo(): boolean;
126
+ /** Number of commands currently in the undo stack. */
127
+ size(): number;
128
+ /** Snapshot of the public history state, suitable for event payloads. */
129
+ snapshot(): HistoryStateSnapshot;
130
+ }
@@ -0,0 +1,59 @@
1
+ import { type OpResult } from '../map/op-result';
2
+ import type { EmapHostInternal } from '../map/emap-host';
3
+ import type { MapshaperDataset } from '../types/mapshaper-types';
4
+ /**
5
+ * Internal-only view of a Transaction used by the runner. Public callers
6
+ * receive the wider {@link Transaction} class.
7
+ */
8
+ export interface TransactionInternal {
9
+ /** Record the first-touch dataset snapshot for `sourceId`, if not already captured. */
10
+ _captureFirstTouch(sourceId: string, before: MapshaperDataset): void;
11
+ }
12
+ /**
13
+ * Atomic multi-step edit unit. Stages every command pushed during its
14
+ * lifetime; `commit()` collapses them into one history entry and
15
+ * `rollback()` restores the dataset + selection to the state at
16
+ * construction.
17
+ *
18
+ * Construct via `Emap.beginTransaction()` — direct construction is
19
+ * supported for tests but bypasses the Emap host wiring.
20
+ */
21
+ export declare class Transaction implements TransactionInternal {
22
+ private readonly _host;
23
+ private readonly _datasetSnapshots;
24
+ private readonly _selectionSnapshot;
25
+ private _closed;
26
+ constructor(host: EmapHostInternal);
27
+ /**
28
+ * Internal — invoked by the runner the first time each source's
29
+ * dataset is about to be swapped within this transaction. The dataset
30
+ * passed here is the pre-op snapshot the runner already produced for
31
+ * its own undo bookkeeping; we keep a reference so rollback can
32
+ * restore the source to its true pre-transaction state regardless of
33
+ * how many ops touched it later.
34
+ */
35
+ _captureFirstTouch(sourceId: string, before: MapshaperDataset): void;
36
+ /** True iff `commit()` / `rollback()` has not been called yet. */
37
+ get isOpen(): boolean;
38
+ /**
39
+ * Drain the capture buffer, push a single `CompositeCommand` wrapping
40
+ * every staged child to the undo stack (no-op if nothing was staged),
41
+ * and close the transaction. Returns `OK` on success or
42
+ * `Err.hostRemoved()` if the host was torn down mid-transaction.
43
+ *
44
+ * The composite's children are NOT re-executed — their effects were
45
+ * applied as each child was originally captured.
46
+ */
47
+ commit(label: string): Promise<OpResult>;
48
+ /**
49
+ * Discard every staged command, restore each touched source's dataset
50
+ * to its pre-transaction snapshot, restore the selection, and close
51
+ * the transaction. Fires `selectionchange`, `historychange`, and
52
+ * schedules a render.
53
+ *
54
+ * Idempotent only in the sense that calling it twice throws — once
55
+ * the transaction is closed it cannot be re-used.
56
+ */
57
+ rollback(): void;
58
+ private _end;
59
+ }