@istar-ts/core 0.7.0 → 0.8.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.ts CHANGED
@@ -68,6 +68,214 @@ export declare function isContributionLabel(value: string): value is Contributio
68
68
  /** `'istar.Goal'` → `'Goal'` */
69
69
  export declare function shortKindName(kind: ElementKind | LinkKind): string;
70
70
  //#endregion
71
+ //#region src/constraints.d.ts
72
+ export type ConstraintCode = "unknown-element" | "unknown-link-kind" | "invalid-source" | "invalid-target" | "actor-types-differ" | "self-link" | "duplicate-link" | "dependum-endpoint" | "same-actor" | "different-actors" | "refined-depender" | "contributed-depender" | "depender-target" | "mixed-refinement" | "contribution-and-qualification";
73
+ export type LinkCheck = {
74
+ ok: true;
75
+ } | {
76
+ ok: false;
77
+ reason: string;
78
+ code: ConstraintCode;
79
+ };
80
+ export interface CanLinkOptions<EK extends string = ElementKind, LK extends string = LinkKind> {
81
+ /** Default: the model's metamodel, or iStar 2.0. */
82
+ readonly metamodel?: Metamodel<EK, LK>;
83
+ }
84
+ /**
85
+ * Checks whether a link of `kind` may be added from `source` to `target` in `model`.
86
+ *
87
+ * For dependency links, `source` is the depender and `target` the dependee (an actor or one of
88
+ * its inner elements); the dependum sits between them and is not part of the check.
89
+ *
90
+ * Extended kinds (see `extendMetamodel`) are checked with the rules of the kind they behave
91
+ * like, or with their declarative rules, then with their extra predicate.
92
+ */
93
+ export declare function canLink<EK extends string = ElementKind, LK extends string = LinkKind>(model: IstarModel<EK, LK>, source: string | IstarElement<EK>, target: string | IstarElement<EK>, kind: LK, options?: CanLinkOptions<EK, LK>): LinkCheck;
94
+ /**
95
+ * What an extension's `check` predicate receives: the model, the endpoints, and the graph
96
+ * queries the iStar 2.0 rules use.
97
+ */
98
+ export interface LinkRuleContext {
99
+ readonly model: AnyIstarModel;
100
+ readonly metamodel: AnyMetamodel;
101
+ /** The link kind being added. */
102
+ readonly kind: string;
103
+ readonly source: IstarElement<string>;
104
+ readonly target: IstarElement<string>;
105
+ /** A link (optionally of `kind`, or a kind behaving like it) joins `a` and `b`, either way. */
106
+ isThereLinkBetween(a: IstarElement<string>, b: IstarElement<string>, kind?: string): boolean;
107
+ /** `element` is the source of a link of `kind` (or a kind behaving like it). */
108
+ isSourceOfType(element: IstarElement<string>, kind: string): boolean;
109
+ /** `element` is the target of a link of `kind` (or a kind behaving like it). */
110
+ isTargetOfType(element: IstarElement<string>, kind: string): boolean;
111
+ }
112
+ export interface ModelIssue<LK extends string = LinkKind> {
113
+ readonly linkId: string;
114
+ readonly kind: LK;
115
+ readonly source: string;
116
+ readonly target: string;
117
+ readonly code: ConstraintCode;
118
+ readonly message: string;
119
+ }
120
+ /**
121
+ * Re-validates every link of a model, the way piStar does when loading a file: dependencies
122
+ * first (each checked before its own links are added), then the remaining links in file
123
+ * order, each against the graph built so far. Invalid links are reported, not removed.
124
+ */
125
+ export declare function validateModel<EK extends string, LK extends string>(model: IstarModel<EK, LK>, options: CanLinkOptions<EK, LK>): ModelIssue<LK>[];
126
+ export declare function validateModel<EK extends string, LK extends string>(model: IstarModel<EK, LK>): ModelIssue<LK>[];
127
+ export declare function validateModel(model: IstarModel): ModelIssue[];
128
+ //#endregion
129
+ //#region src/metamodels.d.ts
130
+ export type ElementCategory = "actor" | "node";
131
+ export type LinkCategory = "actor" | "node" | "dependency";
132
+ /** A resolved element kind of a metamodel. */
133
+ export interface ElementKindDefinition<K extends string = string> {
134
+ readonly kind: K;
135
+ readonly category: ElementCategory;
136
+ /** Human-readable name, e.g. "Goal" or "Planning". */
137
+ readonly label: string;
138
+ /** Default size; for actors the initial boundary size. */
139
+ readonly size: Size;
140
+ /** Containment rules (nodes only; actors have none). */
141
+ readonly info?: NodeKindInfo;
142
+ /** The kind whose link rules this kind follows (built-in kinds have none). */
143
+ readonly behavesLike?: string;
144
+ /** The `type` written in piStar files. Equal to `kind` unless declared otherwise. */
145
+ readonly pistarType: string;
146
+ /** Name of the extension that declared it; absent for iStar 2.0 kinds. */
147
+ readonly extension?: string;
148
+ }
149
+ /**
150
+ * Declarative link rules, as piStar-ext's "Create a new Construct" dialog collects them:
151
+ * which kinds may be the source and target. Entries are kind names (`istar.Goal`,
152
+ * `rationalAgents.Plan`) or categories (`node`, `actor`, `*`). A kind name also matches kinds
153
+ * that behave like it, so `istar.Task` accepts a Planning that behaves like a Task.
154
+ */
155
+ export interface LinkRules {
156
+ readonly sources: readonly string[];
157
+ readonly targets: readonly string[];
158
+ /**
159
+ * Source and target must belong to the same actor (iStar 2.0 Guide, page 14). Default true
160
+ * for node links, ignored for actor links.
161
+ */
162
+ readonly sameActor?: boolean;
163
+ /** Allow a dependum as source or target. Default false. */
164
+ readonly allowDependum?: boolean;
165
+ /** Allow a link from an element onto itself. Default false. */
166
+ readonly allowSelf?: boolean;
167
+ /**
168
+ * At most one link `'kind'` of this kind, or `'any'` link at all, between the same two
169
+ * elements (in either direction); `false` for no limit. Default `'kind'`.
170
+ */
171
+ readonly unique?: "kind" | "any" | false;
172
+ }
173
+ /** A resolved link kind of a metamodel. */
174
+ export interface LinkKindDefinition<K extends string = string> {
175
+ readonly kind: K;
176
+ readonly category: LinkCategory;
177
+ readonly label: string;
178
+ readonly info: LinkKindInfo;
179
+ /** The link kind whose rules (and meaning, for other rules) this kind takes on. */
180
+ readonly behavesLike?: string;
181
+ /** Declarative rules, for link kinds that don't behave like another kind. */
182
+ readonly rules?: LinkRules;
183
+ /** An extra predicate, checked after the inherited or declarative rules pass. */
184
+ readonly check?: (context: LinkRuleContext) => LinkCheck;
185
+ readonly pistarType: string;
186
+ readonly extension?: string;
187
+ }
188
+ /** A metamodel: the element and link kinds a model may use, and their rules. */
189
+ export interface Metamodel<EK extends string = ElementKind, LK extends string = LinkKind> {
190
+ /** `istar-2.0`, followed by the names of the extensions applied, e.g. `istar-2.0+rationalAgents`. */
191
+ readonly name: string;
192
+ readonly extensions: readonly string[];
193
+ /** In declaration order: iStar 2.0 kinds first, then each extension's. */
194
+ readonly elements: ReadonlyMap<EK, ElementKindDefinition<EK>>;
195
+ readonly links: ReadonlyMap<LK, LinkKindDefinition<LK>>;
196
+ /** `type` in piStar files → kind. */
197
+ readonly elementsByPistarType: ReadonlyMap<string, EK>;
198
+ readonly linksByPistarType: ReadonlyMap<string, LK>;
199
+ }
200
+ /** The kinds of a metamodel, as type-level unions. */
201
+ export type ElementKindOf<M> = M extends Metamodel<infer EK, string> ? EK : never;
202
+ export type LinkKindOf<M> = M extends Metamodel<string, infer LK> ? LK : never;
203
+ /** A metamodel of any dialect, for code that handles every kind generically. */
204
+ export type AnyMetamodel = Metamodel<string, string>;
205
+ /** iStar 2.0, as the piStar tool implements it. The default metamodel everywhere. */
206
+ export declare const ISTAR_2_0: Metamodel;
207
+ export interface ElementKindDeclaration<K extends string = string> {
208
+ /** Namespaced kind name, e.g. `rationalAgents.Planning`. */
209
+ readonly kind: K;
210
+ /** Default: the part after the namespace ("Planning"). */
211
+ readonly label?: string;
212
+ /** Required unless `behavesLike` is given (then it is the same category). */
213
+ readonly category?: ElementCategory;
214
+ /** An existing element kind whose link rules this kind follows, e.g. `istar.Task`. */
215
+ readonly behavesLike?: string;
216
+ /** Containment rules for nodes. Default: those of `behavesLike`, else piStar-ext's (inner, dependum). */
217
+ readonly info?: Partial<NodeKindInfo>;
218
+ /** Default: that of `behavesLike`, else piStar-ext's 90×55 for nodes and 200×120 for actors. */
219
+ readonly size?: Size;
220
+ /**
221
+ * The `type` used in piStar files, when it differs from `kind`. piStar-ext saves its new
222
+ * constructs as `istar.<Name>`, so `pistarType: 'istar.Planning'` reads its files.
223
+ */
224
+ readonly pistarType?: string;
225
+ }
226
+ export interface LinkKindDeclaration<K extends string = string> {
227
+ readonly kind: K;
228
+ readonly label?: string;
229
+ /** Default: that of `behavesLike`, else `node`. */
230
+ readonly category?: LinkCategory;
231
+ /** An existing link kind whose rules this kind takes on, e.g. `istar.OrRefinementLink`. */
232
+ readonly behavesLike?: string;
233
+ /** Declarative rules; give these or `behavesLike`, not both. */
234
+ readonly rules?: LinkRules;
235
+ /** An extra predicate, checked after the other rules pass. */
236
+ readonly check?: (context: LinkRuleContext) => LinkCheck;
237
+ /** Default: that of `behavesLike`, else none (no fixed label, no changeable value). */
238
+ readonly info?: LinkKindInfo;
239
+ readonly pistarType?: string;
240
+ }
241
+ /** A named set of new kinds, applied to a metamodel with `extendMetamodel`. */
242
+ export interface MetamodelExtension<NEK extends string = string, NLK extends string = string> {
243
+ /** Identifies the extension, e.g. `rationalAgents`. */
244
+ readonly name: string;
245
+ readonly elements?: readonly ElementKindDeclaration<NEK>[];
246
+ readonly links?: readonly LinkKindDeclaration<NLK>[];
247
+ }
248
+ export declare class MetamodelError extends Error {
249
+ override name: string;
250
+ }
251
+ /**
252
+ * Declares an extension, keeping its kind names as literal types (so `extendMetamodel` can
253
+ * type the result). Identity at runtime.
254
+ */
255
+ export declare function defineMetamodelExtension<const NEK extends string = never, const NLK extends string = never>(extension: MetamodelExtension<NEK, NLK>): MetamodelExtension<NEK, NLK>;
256
+ /**
257
+ * Returns a new metamodel with the extension's kinds added. `base` is not modified.
258
+ *
259
+ * Throws `MetamodelError` when a kind name isn't namespaced, uses the reserved `istar.`
260
+ * prefix, collides with an existing kind or piStar type, or refers to an unknown kind.
261
+ */
262
+ export declare function extendMetamodel<EK extends string, LK extends string, const NEK extends string = never, const NLK extends string = never>(base: Metamodel<EK, LK>, extension: MetamodelExtension<NEK, NLK>): Metamodel<EK | NEK, LK | NLK>;
263
+ export declare function elementKindDefinition(metamodel: AnyMetamodel, kind: string): ElementKindDefinition | undefined;
264
+ export declare function linkKindDefinition(metamodel: AnyMetamodel, kind: string): LinkKindDefinition | undefined;
265
+ /** True for actor-category kinds (Actor, Agent, Role and extensions behaving like them). */
266
+ export declare function isActorKindIn(metamodel: AnyMetamodel, kind: string): boolean;
267
+ /** True for node-category kinds (intentional elements, built-in or extended). */
268
+ export declare function isNodeKindIn(metamodel: AnyMetamodel, kind: string): boolean;
269
+ /**
270
+ * The built-in (or rule-carrying) kind an element kind ultimately behaves like: `istar.Task`
271
+ * for a Planning that behaves like a Task; the kind itself when it behaves like nothing.
272
+ */
273
+ export declare function effectiveElementKind(metamodel: AnyMetamodel, kind: string): string;
274
+ /** Like `effectiveElementKind`, for link kinds. */
275
+ export declare function effectiveLinkKind(metamodel: AnyMetamodel, kind: string): string;
276
+ /** True when `kind` is `ancestor` or (transitively) behaves like it. */
277
+ export declare function elementBehavesLike(metamodel: AnyMetamodel, kind: string, ancestor: string): boolean;
278
+ //#endregion
71
279
  //#region src/model.d.ts
72
280
  /**
73
281
  * piStar stores every custom property value as a string (e.g. `"initialValue": "false"`).
@@ -94,7 +302,11 @@ export interface LinkDisplay {
94
302
  readonly vertices?: readonly Point[];
95
303
  readonly [key: string]: unknown;
96
304
  }
97
- export interface IstarElement<K extends ElementKind = ElementKind> {
305
+ /**
306
+ * An element of the model. `K` is the kind union: iStar 2.0's by default, wider for models of an
307
+ * extended metamodel (see `extendMetamodel`).
308
+ */
309
+ export interface IstarElement<K extends string = ElementKind> {
98
310
  readonly id: string;
99
311
  readonly kind: K;
100
312
  /** The element's label; `text` in the save file. */
@@ -120,7 +332,7 @@ export interface IstarElement<K extends ElementKind = ElementKind> {
120
332
  }
121
333
  export type IstarActor = IstarElement<ActorKind>;
122
334
  export type IstarNode = IstarElement<NodeKind>;
123
- export interface IstarLink<K extends LinkKind = LinkKind> {
335
+ export interface IstarLink<K extends string = LinkKind> {
124
336
  readonly id: string;
125
337
  readonly kind: K;
126
338
  readonly source: string;
@@ -142,10 +354,12 @@ export interface Diagram {
142
354
  /**
143
355
  * An immutable iStar model. Maps preserve insertion order, which is the order elements and
144
356
  * links are written back to disk.
357
+ *
358
+ * `EK`/`LK` are the element and link kind unions; they default to iStar 2.0's.
145
359
  */
146
- export interface IstarModel {
147
- readonly elements: ReadonlyMap<string, IstarElement>;
148
- readonly links: ReadonlyMap<string, IstarLink>;
360
+ export interface IstarModel<EK extends string = ElementKind, LK extends string = LinkKind> {
361
+ readonly elements: ReadonlyMap<string, IstarElement<EK>>;
362
+ readonly links: ReadonlyMap<string, IstarLink<LK>>;
149
363
  readonly diagram?: Diagram;
150
364
  readonly tool?: string;
151
365
  readonly istar?: string;
@@ -159,50 +373,48 @@ export interface IstarModel {
159
373
  export declare const PISTAR_TOOL = "pistar.2.1.0";
160
374
  export declare const ISTAR_VERSION = "2.0";
161
375
  export declare const DEFAULT_DIAGRAM: Diagram;
376
+ /** A model of any dialect, for code that handles every kind generically. */
377
+ export type AnyIstarModel = IstarModel<string, string>;
378
+ /**
379
+ * Associates `metamodel` with `model` and returns the same model, typed for it. Use when a
380
+ * model was built without the library's operations (e.g. with an object spread), which loses
381
+ * the association.
382
+ */
383
+ export declare function withMetamodel<EK extends string, LK extends string>(model: IstarModel<string, string>, metamodel: Metamodel<EK, LK>): IstarModel<EK, LK>;
384
+ /** Gives `to` the metamodel of `from` (used for every model an operation derives). */
385
+ export declare function inheritMetamodel<M extends IstarModel<string, string>>(from: IstarModel<string, string>, to: M): M;
386
+ export declare function createEmptyModel<EK extends string, LK extends string>(diagram: Diagram | undefined, options: {
387
+ metamodel: Metamodel<EK, LK>;
388
+ }): IstarModel<EK, LK>;
162
389
  export declare function createEmptyModel(diagram?: Diagram): IstarModel;
163
- export declare function isActor(element: IstarElement | undefined): element is IstarActor;
164
- export declare function isNode(element: IstarElement | undefined): element is IstarNode;
165
- /** Inner elements of an actor, in model order. */
166
- export declare function childrenOf(model: IstarModel, actorId: string): IstarElement[];
167
- /** Links that have the element as source or target. */
168
- export declare function linksOf(model: IstarModel, elementId: string): IstarLink[];
169
- /** For a dependum, the two halves of its dependency: depender → dependum → dependee. */
170
- export declare function dependencyLinksOf(model: IstarModel, dependumId: string): {
171
- inbound?: IstarLink;
172
- outbound?: IstarLink;
173
- };
174
- //#endregion
175
- //#region src/constraints.d.ts
176
- export type ConstraintCode = "unknown-element" | "unknown-link-kind" | "invalid-source" | "invalid-target" | "actor-types-differ" | "self-link" | "duplicate-link" | "dependum-endpoint" | "same-actor" | "different-actors" | "refined-depender" | "contributed-depender" | "depender-target" | "mixed-refinement" | "contribution-and-qualification";
177
- export type LinkCheck = {
178
- ok: true;
179
- } | {
180
- ok: false;
181
- reason: string;
182
- code: ConstraintCode;
183
- };
184
- type ElementRef = string | IstarElement;
185
390
  /**
186
- * Checks whether a link of `kind` may be added from `source` to `target` in `model`.
187
- *
188
- * For `istar.DependencyLink`, `source` is the depender and `target` the dependee (an actor or
189
- * one of its inner elements); the dependum sits between them and is not part of the check.
391
+ * The metamodel a model was read or created with (see `parsePistar`, `createEmptyModel`), or
392
+ * iStar 2.0. Constraints, operations and serialization use it unless given another one.
190
393
  */
191
- export declare function canLink(model: IstarModel, source: ElementRef, target: ElementRef, kind: LinkKind): LinkCheck;
192
- export interface ModelIssue {
193
- readonly linkId: string;
194
- readonly kind: LinkKind;
195
- readonly source: string;
196
- readonly target: string;
197
- readonly code: ConstraintCode;
198
- readonly message: string;
199
- }
394
+ export declare function metamodelOf<EK extends string, LK extends string>(model: IstarModel<EK, LK>): Metamodel<EK, LK>;
200
395
  /**
201
- * Re-validates every link of a model, the way piStar does when loading a file: dependencies
202
- * first (each checked before its own links are added), then the remaining links in file
203
- * order, each against the graph built so far. Invalid links are reported, not removed.
396
+ * True for iStar 2.0 actors (Actor, Agent, Role). One argument, so it is safe as an array
397
+ * callback (`elements.filter(isActor)`). For extended actor kinds use `isActorIn(metamodel)`.
204
398
  */
205
- export declare function validateModel(model: IstarModel): ModelIssue[];
399
+ export declare function isActor(element: IstarElement<string> | undefined): element is IstarActor;
400
+ /** True for iStar 2.0 intentional elements. For extended kinds use `isNodeIn(metamodel)`. */
401
+ export declare function isNode(element: IstarElement<string> | undefined): element is IstarNode;
402
+ /**
403
+ * A predicate for actor-category elements of `metamodel`, extended actor kinds included:
404
+ * `elements.filter(isActorIn(metamodelOf(model)))`.
405
+ */
406
+ export declare function isActorIn(metamodel: AnyMetamodel): (element: IstarElement<string> | undefined) => boolean;
407
+ /** A predicate for node-category elements of `metamodel`, extended node kinds included. */
408
+ export declare function isNodeIn(metamodel: AnyMetamodel): (element: IstarElement<string> | undefined) => boolean;
409
+ /** Inner elements of an actor, in model order. */
410
+ export declare function childrenOf<EK extends string, LK extends string>(model: IstarModel<EK, LK>, actorId: string): IstarElement<EK>[];
411
+ /** Links that have the element as source or target. */
412
+ export declare function linksOf<EK extends string, LK extends string>(model: IstarModel<EK, LK>, elementId: string): IstarLink<LK>[];
413
+ /** For a dependum, the two halves of its dependency: depender → dependum → dependee. */
414
+ export declare function dependencyLinksOf<EK extends string, LK extends string>(model: IstarModel<EK, LK>, dependumId: string): {
415
+ inbound?: IstarLink<LK>;
416
+ outbound?: IstarLink<LK>;
417
+ };
206
418
  //#endregion
207
419
  //#region src/serialization.d.ts
208
420
  export interface PistarElementJson {
@@ -254,6 +466,10 @@ export interface PistarFile {
254
466
  export declare class PistarParseError extends Error {
255
467
  override name: string;
256
468
  }
469
+ /** Thrown by `toPistar` for a kind its metamodel doesn't know (rather than writing it wrong). */
470
+ export declare class PistarWriteError extends Error {
471
+ override name: string;
472
+ }
257
473
  /**
258
474
  * Parse-time bookkeeping that lets `toPistar` reproduce the original key order. It has no
259
475
  * meaning for the model itself and may be dropped.
@@ -265,20 +481,33 @@ export interface SourceLayout {
265
481
  readonly display: readonly string[];
266
482
  }
267
483
  /** The key order recorded when `model` was parsed, if it came from `parsePistar`. */
268
- export declare function getSourceLayout(model: IstarModel): SourceLayout | undefined;
484
+ export declare function getSourceLayout<EK extends string, LK extends string>(model: IstarModel<EK, LK>): SourceLayout | undefined;
269
485
  /**
270
486
  * Carries the recorded key order over to a model derived from `from` (the store does this for
271
487
  * every edit, so saving an edited file keeps a stable diff).
272
488
  */
273
- export declare function inheritSourceLayout<M extends IstarModel>(from: IstarModel, to: M): M;
489
+ export declare function inheritSourceLayout<M extends IstarModel<string, string>>(from: IstarModel<string, string>, to: M): M;
274
490
  /**
275
491
  * Parses a piStar save file (JSON text or an already-parsed object). The input is not mutated.
276
492
  *
277
493
  * Unlike the piStar tool, elements with `x` or `y` equal to 0 are kept: upstream's
278
494
  * `if (element.x && element.y)` silently drops them, which looks unintended.
279
495
  */
496
+ export interface ParsePistarOptions<EK extends string = ElementKind, LK extends string = LinkKind> {
497
+ /**
498
+ * The metamodel whose kinds the file may use. Default iStar 2.0: any other `type` throws,
499
+ * as in the piStar tool. The parsed model remembers it (see `metamodelOf`).
500
+ */
501
+ readonly metamodel?: Metamodel<EK, LK>;
502
+ }
503
+ export declare function parsePistar<EK extends string, LK extends string>(input: string | PistarFile | Record<string, unknown>, options: ParsePistarOptions<EK, LK> & {
504
+ readonly metamodel: Metamodel<EK, LK>;
505
+ }): IstarModel<EK, LK>;
506
+ export declare function parsePistar(input: string | PistarFile | Record<string, unknown>, options: ParsePistarOptions): IstarModel;
280
507
  export declare function parsePistar(input: string | PistarFile | Record<string, unknown>): IstarModel;
281
508
  export interface ToPistarOptions {
509
+ /** Default: the model's metamodel, or iStar 2.0. Decides each kind's `type` and category. */
510
+ metamodel?: AnyMetamodel;
282
511
  /**
283
512
  * Value for `saveDate`. Defaults to the model's own `saveDate` (so a load/save round trip is
284
513
  * lossless), or the current time for models that never had one. Pass `new Date()` when
@@ -287,9 +516,9 @@ export interface ToPistarOptions {
287
516
  saveDate?: string | Date;
288
517
  }
289
518
  /** Builds the save-file object for a model. `toPistar` is this plus `JSON.stringify`. */
290
- export declare function toPistarObject(model: IstarModel, options?: ToPistarOptions): PistarFile;
519
+ export declare function toPistarObject<EK extends string, LK extends string>(input: IstarModel<EK, LK>, options?: ToPistarOptions): PistarFile;
291
520
  /** Serializes a model to piStar's JSON text (2-space indentation, no trailing newline). */
292
- export declare function toPistar(model: IstarModel, options?: ToPistarOptions): string;
521
+ export declare function toPistar<EK extends string, LK extends string>(model: IstarModel<EK, LK>, options?: ToPistarOptions): string;
293
522
  declare namespace operations_d_exports {
294
523
  export { AddDependencyResult, ConnectOptions, ConnectResult, ElementPatch, IdGenerator, LinkPatch, ModelOperationError, NewDependency, NewElement, NewLink, OperationContext, addDependency, addElement, connect, defaultIdGenerator, dependencyEnds, disconnect, moveElement, nestElement, removeElement, removeElements, updateDiagram, updateElement, updateLink };
295
524
  }
@@ -302,21 +531,21 @@ export declare const defaultIdGenerator: IdGenerator;
302
531
  export interface OperationContext {
303
532
  readonly createId?: IdGenerator;
304
533
  }
305
- export interface NewElement {
306
- readonly kind: ElementKind;
534
+ export interface NewElement<K extends string = ElementKind> {
535
+ readonly kind: K;
307
536
  readonly x: number;
308
537
  readonly y: number;
309
538
  readonly id?: string;
310
- /** Defaults to the kind's short name ("Goal"), like piStar. */
539
+ /** Defaults to the kind's label ("Goal"), like piStar. */
311
540
  readonly name?: string;
312
541
  /** Actor to place the element in. Required in practice for iStar nodes (see NodeKindInfo). */
313
542
  readonly parent?: string;
314
543
  readonly customProperties?: CustomProperties;
315
544
  readonly display?: ElementDisplay;
316
545
  }
317
- export declare function addElement(model: IstarModel, input: NewElement, ctx?: OperationContext): {
318
- model: IstarModel;
319
- element: IstarElement;
546
+ export declare function addElement<EK extends string = ElementKind, LK extends string = LinkKind>(model: IstarModel<EK, LK>, input: NewElement<EK>, ctx?: OperationContext): {
547
+ model: IstarModel<EK, LK>;
548
+ element: IstarElement<EK>;
320
549
  };
321
550
  export interface ElementPatch {
322
551
  readonly name?: string;
@@ -327,26 +556,27 @@ export interface ElementPatch {
327
556
  readonly [key: string]: unknown;
328
557
  } | null;
329
558
  }
330
- export declare function updateElement(model: IstarModel, id: string, patch: ElementPatch): IstarModel;
559
+ export declare function updateElement<EK extends string = ElementKind, LK extends string = LinkKind>(model: IstarModel<EK, LK>, id: string, patch: ElementPatch): IstarModel<EK, LK>;
331
560
  /**
332
561
  * Moves an element to an absolute position. Moving an actor shifts its inner elements by the
333
562
  * same offset.
334
563
  */
335
- export declare function moveElement(model: IstarModel, id: string, x: number, y: number): IstarModel;
564
+ export declare function moveElement<EK extends string = ElementKind, LK extends string = LinkKind>(model: IstarModel<EK, LK>, id: string, x: number, y: number): IstarModel<EK, LK>;
336
565
  /**
337
566
  * Moves an inner element into another actor (or out of any actor with `null`). The element
338
567
  * becomes the actor's last child. Links that become invalid are kept; `validateModel` reports
339
568
  * them.
340
569
  */
341
- export declare function nestElement(model: IstarModel, id: string, parent: string | null): IstarModel;
570
+ export declare function nestElement<EK extends string = ElementKind, LK extends string = LinkKind>(model: IstarModel<EK, LK>, id: string, parent: string | null): IstarModel<EK, LK>;
342
571
  /**
343
572
  * Removes elements and everything that depends on them: inner elements of removed actors,
344
573
  * links touching removed elements, and the rest of any dependency that loses a part.
345
574
  */
346
- export declare function removeElements(model: IstarModel, ids: Iterable<string>): IstarModel;
347
- export declare function removeElement(model: IstarModel, id: string): IstarModel;
348
- export interface NewLink {
349
- readonly kind: Exclude<LinkKind, "istar.DependencyLink">;
575
+ export declare function removeElements<EK extends string = ElementKind, LK extends string = LinkKind>(model: IstarModel<EK, LK>, ids: Iterable<string>): IstarModel<EK, LK>;
576
+ export declare function removeElement<EK extends string = ElementKind, LK extends string = LinkKind>(model: IstarModel<EK, LK>, id: string): IstarModel<EK, LK>;
577
+ export interface NewLink<K extends string = LinkKind> {
578
+ /** Any link kind except dependency kinds (use `addDependency` for those). */
579
+ readonly kind: Exclude<K, DependencyLinkKind>;
350
580
  readonly source: string;
351
581
  readonly target: string;
352
582
  readonly id?: string;
@@ -364,23 +594,24 @@ export interface ConnectOptions extends OperationContext {
364
594
  */
365
595
  readonly tryReversed?: boolean;
366
596
  }
367
- export type ConnectResult = {
597
+ export type ConnectResult<EK extends string = ElementKind, LK extends string = LinkKind> = {
368
598
  ok: true;
369
- model: IstarModel;
370
- link: IstarLink;
599
+ model: IstarModel<EK, LK>;
600
+ link: IstarLink<LK>;
371
601
  reversed: boolean;
372
602
  } | Extract<LinkCheck, {
373
603
  ok: false;
374
604
  }>;
375
605
  /** Adds a link between two elements if the iStar constraints allow it. */
376
- export declare function connect(model: IstarModel, input: NewLink, options?: ConnectOptions): ConnectResult;
377
- export interface NewDependency {
606
+ export declare function connect<EK extends string = ElementKind, LK extends string = LinkKind>(model: IstarModel<EK, LK>, input: NewLink<LK>, options?: ConnectOptions): ConnectResult<EK, LK>;
607
+ export interface NewDependency<EK extends string = ElementKind, LK extends string = LinkKind> {
378
608
  /** The depender: an actor or one of its inner elements. */
379
609
  readonly depender: string;
380
610
  /** The dependee: an actor or one of its inner elements. */
381
611
  readonly dependee: string;
382
612
  readonly dependum: {
383
- readonly kind: NodeKind;
613
+ /** A node kind (built-in or extended) that can be a dependum. */
614
+ readonly kind: Exclude<EK, ActorKind>;
384
615
  readonly name?: string;
385
616
  readonly id?: string;
386
617
  /** Defaults to the midpoint between depender and dependee, as in piStar. */
@@ -388,20 +619,22 @@ export interface NewDependency {
388
619
  readonly y?: number;
389
620
  readonly customProperties?: CustomProperties;
390
621
  };
622
+ /** A dependency link kind. Default `istar.DependencyLink`. */
623
+ readonly linkKind?: LK;
391
624
  readonly linkIds?: readonly [string, string];
392
625
  }
393
- export type AddDependencyResult = {
626
+ export type AddDependencyResult<EK extends string = ElementKind, LK extends string = LinkKind> = {
394
627
  ok: true;
395
- model: IstarModel;
396
- dependum: IstarElement;
397
- links: readonly [IstarLink, IstarLink];
628
+ model: IstarModel<EK, LK>;
629
+ dependum: IstarElement<EK>;
630
+ links: readonly [IstarLink<LK>, IstarLink<LK>];
398
631
  } | Extract<LinkCheck, {
399
632
  ok: false;
400
633
  }>;
401
634
  /** Adds depender → dependum → dependee. */
402
- export declare function addDependency(model: IstarModel, input: NewDependency, options?: Omit<ConnectOptions, "tryReversed">): AddDependencyResult;
635
+ export declare function addDependency<EK extends string = ElementKind, LK extends string = LinkKind>(model: IstarModel<EK, LK>, input: NewDependency<EK, LK>, options?: Omit<ConnectOptions, "tryReversed">): AddDependencyResult<EK, LK>;
403
636
  /** Removes a link. Removing either half of a dependency removes the whole dependency. */
404
- export declare function disconnect(model: IstarModel, id: string): IstarModel;
637
+ export declare function disconnect<EK extends string = ElementKind, LK extends string = LinkKind>(model: IstarModel<EK, LK>, id: string): IstarModel<EK, LK>;
405
638
  export interface LinkPatch {
406
639
  /** `null` removes it. */
407
640
  readonly label?: string | null;
@@ -411,10 +644,10 @@ export interface LinkPatch {
411
644
  readonly [key: string]: unknown;
412
645
  } | null;
413
646
  }
414
- export declare function updateLink(model: IstarModel, id: string, patch: LinkPatch): IstarModel;
415
- export declare function updateDiagram(model: IstarModel, patch: Partial<Diagram>): IstarModel;
647
+ export declare function updateLink<EK extends string = ElementKind, LK extends string = LinkKind>(model: IstarModel<EK, LK>, id: string, patch: LinkPatch): IstarModel<EK, LK>;
648
+ export declare function updateDiagram<EK extends string = ElementKind, LK extends string = LinkKind>(model: IstarModel<EK, LK>, patch: Partial<Diagram>): IstarModel<EK, LK>;
416
649
  /** Where dependency depender/dependee currently point (see `dependencyLinksOf`). */
417
- export declare function dependencyEnds(model: IstarModel, dependumId: string): {
650
+ export declare function dependencyEnds<EK extends string, LK extends string>(model: IstarModel<EK, LK>, dependumId: string): {
418
651
  depender?: string;
419
652
  dependee?: string;
420
653
  };
@@ -460,40 +693,45 @@ export type ModelChange = {
460
693
  } | {
461
694
  type: "replace";
462
695
  };
463
- export interface ModelChangeEvent {
464
- readonly model: IstarModel;
465
- readonly previous: IstarModel;
696
+ export interface ModelChangeEvent<EK extends string = ElementKind, LK extends string = LinkKind> {
697
+ readonly model: IstarModel<EK, LK>;
698
+ readonly previous: IstarModel<EK, LK>;
466
699
  /** `undo`/`redo`/`load` carry no changes; a transaction carries all of its changes. */
467
700
  readonly changes: readonly ModelChange[];
468
701
  readonly source: "edit" | "undo" | "redo" | "load";
469
702
  }
470
- export type ModelListener = (event: ModelChangeEvent) => void;
471
- export interface ModelStoreOptions {
703
+ export type ModelListener<EK extends string = ElementKind, LK extends string = LinkKind> = (event: ModelChangeEvent<EK, LK>) => void;
704
+ export interface ModelStoreOptions<EK extends string = ElementKind, LK extends string = LinkKind> {
705
+ /**
706
+ * Metamodel for the default empty model, when no initial model is given. A given initial
707
+ * model keeps its own (see `metamodelOf`).
708
+ */
709
+ readonly metamodel?: Metamodel<EK, LK>;
472
710
  readonly createId?: IdGenerator;
473
711
  /** Maximum number of undo steps kept. Default 100. */
474
712
  readonly historyLimit?: number;
475
713
  }
476
- export interface ModelStore {
477
- getModel(): IstarModel;
714
+ export interface ModelStore<EK extends string = ElementKind, LK extends string = LinkKind> {
715
+ getModel(): IstarModel<EK, LK>;
478
716
  /** Returns an unsubscribe function. */
479
- subscribe(listener: ModelListener): () => void;
480
- canLink(source: string | IstarElement, target: string | IstarElement, kind: LinkKind): LinkCheck;
481
- addElement(input: NewElement): IstarElement;
717
+ subscribe(listener: ModelListener<EK, LK>): () => void;
718
+ canLink(source: string | IstarElement<EK>, target: string | IstarElement<EK>, kind: LK): LinkCheck;
719
+ addElement(input: NewElement<EK>): IstarElement<EK>;
482
720
  updateElement(id: string, patch: ElementPatch): void;
483
721
  moveElement(id: string, x: number, y: number): void;
484
722
  nestElement(id: string, parent: string | null): void;
485
723
  removeElement(id: string): void;
486
724
  removeElements(ids: Iterable<string>): void;
487
725
  setCollapsed(actorId: string, collapsed: boolean): void;
488
- connect(input: NewLink, options?: Omit<ConnectOptions, "createId">): ConnectResult;
489
- addDependency(input: NewDependency, options?: Omit<ConnectOptions, "createId" | "tryReversed">): AddDependencyResult;
726
+ connect(input: NewLink<LK>, options?: Omit<ConnectOptions, "createId">): ConnectResult<EK, LK>;
727
+ addDependency(input: NewDependency<EK, LK>, options?: Omit<ConnectOptions, "createId" | "tryReversed">): AddDependencyResult<EK, LK>;
490
728
  updateLink(id: string, patch: LinkPatch): void;
491
729
  disconnect(id: string): void;
492
730
  updateDiagram(patch: Partial<Diagram>): void;
493
731
  /** Replaces the model as one undoable edit. */
494
- replace(model: IstarModel): void;
732
+ replace(model: IstarModel<EK, LK>): void;
495
733
  /** Replaces the model and clears history (like opening a file in piStar). */
496
- load(model: IstarModel): void;
734
+ load(model: IstarModel<EK, LK>): void;
497
735
  /**
498
736
  * Groups several edits into one undo step and one change event. Nested calls join the
499
737
  * outermost transaction. If `fn` throws, the model is rolled back.
@@ -505,6 +743,10 @@ export interface ModelStore {
505
743
  canRedo(): boolean;
506
744
  clearHistory(): void;
507
745
  }
746
+ export declare function createModelStore<EK extends string, LK extends string>(initial: IstarModel<EK, LK>, options?: ModelStoreOptions<EK, LK>): ModelStore<EK, LK>;
747
+ export declare function createModelStore<EK extends string, LK extends string>(initial: undefined, options: ModelStoreOptions<EK, LK> & {
748
+ readonly metamodel: Metamodel<EK, LK>;
749
+ }): ModelStore<EK, LK>;
508
750
  export declare function createModelStore(initial?: IstarModel, options?: ModelStoreOptions): ModelStore;
509
751
  //#endregion
510
752
  //#region src/properties.d.ts
@@ -551,8 +793,12 @@ export interface PropertyIssue {
551
793
  key: string;
552
794
  message: string;
553
795
  }
554
- export interface PropertySchema<S extends PropertyShape = PropertyShape> {
555
- readonly kind: ElementKind | LinkKind;
796
+ /**
797
+ * Typed custom properties of one element or link kind. `K` is the kind: iStar 2.0's kinds by
798
+ * default; any extension kind (see `extendMetamodel`) is accepted too.
799
+ */
800
+ export interface PropertySchema<S extends PropertyShape = PropertyShape, K extends string = ElementKind | LinkKind> {
801
+ readonly kind: K;
556
802
  readonly shape: S;
557
803
  read(source: CustomProperties | undefined | PropertyOwner): {
558
804
  values: Partial<InferProperties<S>>;
@@ -570,9 +816,9 @@ export interface PropertyOwner {
570
816
  export interface ModelPropertyIssue extends PropertyIssue {
571
817
  id: string;
572
818
  }
573
- export declare function defineProperties<const S extends PropertyShape>(kind: ElementKind | LinkKind, shape: S, options?: {
819
+ export declare function defineProperties<const S extends PropertyShape, const Kind extends string = ElementKind | LinkKind>(kind: Kind, shape: S, options?: {
574
820
  validate?: (values: Partial<InferProperties<S>>) => PropertyIssue[];
575
- }): PropertySchema<S>;
576
- export declare function validateModelProperties(model: IstarModel, schemas: readonly PropertySchema[]): ModelPropertyIssue[];
821
+ }): PropertySchema<S, Kind>;
822
+ export declare function validateModelProperties<EK extends string, LK extends string>(model: IstarModel<EK, LK>, schemas: readonly PropertySchema<PropertyShape, string>[]): ModelPropertyIssue[];
577
823
  //#endregion
578
824
  //# sourceMappingURL=index.d.ts.map