@istar-ts/actions 0.15.0 → 0.15.1

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.
package/dist/index.d.cts CHANGED
@@ -810,6 +810,20 @@ export interface MirrorStoreOptions<EK extends string = ElementKind, LK extends
810
810
  readonly historyLimit?: number;
811
811
  /** Hears a failed update (a transport fault, a file that doesn't parse). Default: ignored. */
812
812
  readonly onError?: (error: unknown) => void;
813
+ /**
814
+ * Shown until the remote's first `requestModel` answers, instead of an empty model (a parsed
815
+ * model, or a piStar file parsed the same way as a pushed one — see `metamodelFor`). Replaced
816
+ * once the remote answers, unless its model is equal.
817
+ */
818
+ readonly initial?: IstarModel<EK, LK> | PistarFile;
819
+ /**
820
+ * The metamodel a pushed or re-requested file is read with, resolved per file (e.g. by its
821
+ * `tool`, with `detectFramework`) instead of the fixed `metamodel`. Keeps the mirror itself
822
+ * dialect-agnostic: a host whose remote may switch a mirror's root metamodel (an iStar mirror
823
+ * shown a KAOS file after `store.replace`) passes this instead of `metamodel`. Default:
824
+ * every file is read with `metamodel` (today's behaviour).
825
+ */
826
+ readonly metamodelFor?: (file: PistarFile) => Metamodel<EK, LK>;
813
827
  }
814
828
  /**
815
829
  * A `ModelStore` whose model is the remote's. Reading (`getModel`, `subscribe`, `canLink`) works
@@ -919,6 +933,19 @@ export declare function createRemoteDispatcher<EK extends string = ElementKind,
919
933
  } = {
920
934
  readonly data: unknown;
921
935
  }>(port: MessagePortLike<E>): ActionDispatcher<EK, LK>;
936
+ /**
937
+ * `dispatcher` as a `StoreActionDispatcher`, for a consumer that asks for its dirty state (a GLSP
938
+ * session over a host's dispatcher, `@istar-ts/glsp`'s `IstarSharedModel`). A dispatcher that has
939
+ * `isDirty` is returned as is (with a no-op `dispose` if it has none); one that doesn't (a
940
+ * `createRemoteDispatcher`, a mirror's) is wrapped, its dirty state tracked from the
941
+ * `setDirtyState` notifications it relays from then on: clean until the first one, since a remote
942
+ * dispatcher doesn't publish the state it had before. `dispose` stops tracking and never disposes
943
+ * the dispatcher itself, which stays its owner's (#249).
944
+ */
945
+ export declare function withDirtyState<EK extends string = ElementKind, LK extends string = LinkKind>(dispatcher: ActionDispatcher<EK, LK> & {
946
+ isDirty?(): boolean;
947
+ dispose?(): void;
948
+ }): StoreActionDispatcher<EK, LK>;
922
949
  //#endregion
923
950
  //#region src/index.d.ts
924
951
  /** Version of the action protocol this package speaks. */
package/dist/index.d.ts CHANGED
@@ -810,6 +810,20 @@ export interface MirrorStoreOptions<EK extends string = ElementKind, LK extends
810
810
  readonly historyLimit?: number;
811
811
  /** Hears a failed update (a transport fault, a file that doesn't parse). Default: ignored. */
812
812
  readonly onError?: (error: unknown) => void;
813
+ /**
814
+ * Shown until the remote's first `requestModel` answers, instead of an empty model (a parsed
815
+ * model, or a piStar file parsed the same way as a pushed one — see `metamodelFor`). Replaced
816
+ * once the remote answers, unless its model is equal.
817
+ */
818
+ readonly initial?: IstarModel<EK, LK> | PistarFile;
819
+ /**
820
+ * The metamodel a pushed or re-requested file is read with, resolved per file (e.g. by its
821
+ * `tool`, with `detectFramework`) instead of the fixed `metamodel`. Keeps the mirror itself
822
+ * dialect-agnostic: a host whose remote may switch a mirror's root metamodel (an iStar mirror
823
+ * shown a KAOS file after `store.replace`) passes this instead of `metamodel`. Default:
824
+ * every file is read with `metamodel` (today's behaviour).
825
+ */
826
+ readonly metamodelFor?: (file: PistarFile) => Metamodel<EK, LK>;
813
827
  }
814
828
  /**
815
829
  * A `ModelStore` whose model is the remote's. Reading (`getModel`, `subscribe`, `canLink`) works
@@ -919,6 +933,19 @@ export declare function createRemoteDispatcher<EK extends string = ElementKind,
919
933
  } = {
920
934
  readonly data: unknown;
921
935
  }>(port: MessagePortLike<E>): ActionDispatcher<EK, LK>;
936
+ /**
937
+ * `dispatcher` as a `StoreActionDispatcher`, for a consumer that asks for its dirty state (a GLSP
938
+ * session over a host's dispatcher, `@istar-ts/glsp`'s `IstarSharedModel`). A dispatcher that has
939
+ * `isDirty` is returned as is (with a no-op `dispose` if it has none); one that doesn't (a
940
+ * `createRemoteDispatcher`, a mirror's) is wrapped, its dirty state tracked from the
941
+ * `setDirtyState` notifications it relays from then on: clean until the first one, since a remote
942
+ * dispatcher doesn't publish the state it had before. `dispose` stops tracking and never disposes
943
+ * the dispatcher itself, which stays its owner's (#249).
944
+ */
945
+ export declare function withDirtyState<EK extends string = ElementKind, LK extends string = LinkKind>(dispatcher: ActionDispatcher<EK, LK> & {
946
+ isDirty?(): boolean;
947
+ dispose?(): void;
948
+ }): StoreActionDispatcher<EK, LK>;
922
949
  //#endregion
923
950
  //#region src/index.d.ts
924
951
  /** Version of the action protocol this package speaks. */
package/dist/index.js CHANGED
@@ -1249,10 +1249,19 @@ const parseWith = parsePistar;
1249
1249
  function createMirrorStore(remote, options = {}) {
1250
1250
  const r = remote;
1251
1251
  const metamodel = options.metamodel;
1252
+ const metamodelFor = options.metamodelFor;
1252
1253
  const limit = options.historyLimit ?? 100;
1253
1254
  const onError = options.onError ?? (() => {});
1254
1255
  const listeners = /* @__PURE__ */ new Set();
1255
- let model = metamodel ? createEmptyModel(void 0, { metamodel }) : createEmptyModel();
1256
+ const parseFile = (file) => {
1257
+ const base = metamodelFor ? metamodelFor(file) : metamodel;
1258
+ return parseWith(file, {
1259
+ ...base ? { metamodel: base } : {},
1260
+ ...options.fileMetamodel ? { fileMetamodel: true } : {}
1261
+ });
1262
+ };
1263
+ const initial = options.initial;
1264
+ let model = (initial === void 0 ? void 0 : initial.elements instanceof Map ? initial : parseFile(initial)) ?? (metamodel ? createEmptyModel(void 0, { metamodel }) : createEmptyModel());
1256
1265
  /** The last file's `"metamodel"` block, as JSON; `undefined` before the first file. */
1257
1266
  let block;
1258
1267
  let undoDepth = 0;
@@ -1264,11 +1273,9 @@ function createMirrorStore(remote, options = {}) {
1264
1273
  let disposed = false;
1265
1274
  const parse = (file) => {
1266
1275
  const nextBlock = JSON.stringify(file[FILE_METAMODEL_KEY] ?? null);
1267
- if (nextBlock === block) return inheritMetamodel(model, parseWith(file, { metamodel: metamodelOf(model) }));
1268
- const parsed = parseWith(file, {
1269
- ...metamodel ? { metamodel } : {},
1270
- ...options.fileMetamodel ? { fileMetamodel: true } : {}
1271
- });
1276
+ const root = metamodelFor?.(file);
1277
+ if (nextBlock === block && (!metamodelFor || root === metamodelOf(model))) return inheritMetamodel(model, parseWith(file, { metamodel: metamodelOf(model) }));
1278
+ const parsed = parseFile(file);
1272
1279
  block = nextBlock;
1273
1280
  return parsed;
1274
1281
  };
@@ -1518,11 +1525,44 @@ function createRemoteDispatcher(port) {
1518
1525
  }
1519
1526
  };
1520
1527
  }
1528
+ /**
1529
+ * `dispatcher` as a `StoreActionDispatcher`, for a consumer that asks for its dirty state (a GLSP
1530
+ * session over a host's dispatcher, `@istar-ts/glsp`'s `IstarSharedModel`). A dispatcher that has
1531
+ * `isDirty` is returned as is (with a no-op `dispose` if it has none); one that doesn't (a
1532
+ * `createRemoteDispatcher`, a mirror's) is wrapped, its dirty state tracked from the
1533
+ * `setDirtyState` notifications it relays from then on: clean until the first one, since a remote
1534
+ * dispatcher doesn't publish the state it had before. `dispose` stops tracking and never disposes
1535
+ * the dispatcher itself, which stays its owner's (#249).
1536
+ */
1537
+ function withDirtyState(dispatcher) {
1538
+ const own = dispatcher.isDirty;
1539
+ if (typeof own === "function") {
1540
+ if (typeof dispatcher.dispose === "function") return dispatcher;
1541
+ return {
1542
+ dispatch: (action, options) => dispatcher.dispatch(action, options),
1543
+ subscribe: (listener) => dispatcher.subscribe(listener),
1544
+ isDirty: () => own.call(dispatcher),
1545
+ dispose: () => void 0
1546
+ };
1547
+ }
1548
+ let dirty = false;
1549
+ const unsubscribe = dispatcher.subscribe((action) => {
1550
+ if (action.kind === "setDirtyState") dirty = action.isDirty;
1551
+ });
1552
+ return {
1553
+ dispatch: (action, options) => dispatcher.dispatch(action, options),
1554
+ subscribe: (listener) => dispatcher.subscribe(listener),
1555
+ isDirty: () => dirty,
1556
+ dispose: () => {
1557
+ unsubscribe();
1558
+ }
1559
+ };
1560
+ }
1521
1561
  //#endregion
1522
1562
  //#region src/index.ts
1523
1563
  /** Version of the action protocol this package speaks. */
1524
1564
  const ACTIONS_PROTOCOL_VERSION = "0.0.0";
1525
1565
  //#endregion
1526
- export { ACTIONS_PROTOCOL_VERSION, HANDLED_ACTION_KINDS, connectDispatcher, contextActionsFor, contextText, createActionDispatcher, createMirrorStore, createRemoteDispatcher, diagnosticToMarker, hostToolContext, injectCreatedIds, isOperation, isRequestAction, markerToDiagnostic, metamodelContext, metamodelContextProvider, metamodelContextText, paletteFromMetamodel, readOnlyDispatcher, typeHintsFor };
1566
+ export { ACTIONS_PROTOCOL_VERSION, HANDLED_ACTION_KINDS, connectDispatcher, contextActionsFor, contextText, createActionDispatcher, createMirrorStore, createRemoteDispatcher, diagnosticToMarker, hostToolContext, injectCreatedIds, isOperation, isRequestAction, markerToDiagnostic, metamodelContext, metamodelContextProvider, metamodelContextText, paletteFromMetamodel, readOnlyDispatcher, typeHintsFor, withDirtyState };
1527
1567
 
1528
1568
  //# sourceMappingURL=index.js.map