@istar-ts/core 0.11.0 → 0.13.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.
- package/README.md +143 -2
- package/dist/index.cjs +1044 -198
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +375 -22
- package/dist/index.d.ts +375 -22
- package/dist/index.js +1016 -199
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -69,7 +69,7 @@ export declare function isContributionLabel(value: string): value is Contributio
|
|
|
69
69
|
export declare function shortKindName(kind: ElementKind | LinkKind): string;
|
|
70
70
|
//#endregion
|
|
71
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";
|
|
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" | "hub-target" | "incomplete-hub";
|
|
73
73
|
export type LinkCheck = {
|
|
74
74
|
ok: true;
|
|
75
75
|
} | {
|
|
@@ -77,6 +77,11 @@ export type LinkCheck = {
|
|
|
77
77
|
reason: string;
|
|
78
78
|
code: ConstraintCode;
|
|
79
79
|
};
|
|
80
|
+
/**
|
|
81
|
+
* True for a link, as opposed to an element: the target of a link kind whose rules target links
|
|
82
|
+
* (see `LinkRules`) may be either.
|
|
83
|
+
*/
|
|
84
|
+
export declare function isLinkRef<EK extends string, LK extends string>(value: IstarElement<EK> | IstarLink<LK>): value is IstarLink<LK>;
|
|
80
85
|
export interface CanLinkOptions<EK extends string = ElementKind, LK extends string = LinkKind> {
|
|
81
86
|
/** Default: the model's metamodel, or iStar 2.0. */
|
|
82
87
|
readonly metamodel?: Metamodel<EK, LK>;
|
|
@@ -89,8 +94,13 @@ export interface CanLinkOptions<EK extends string = ElementKind, LK extends stri
|
|
|
89
94
|
*
|
|
90
95
|
* Extended kinds (see `extendMetamodel`) are checked with the rules of the kind they behave
|
|
91
96
|
* like, or with their declarative rules, then with their extra predicate.
|
|
97
|
+
*
|
|
98
|
+
* `target` may be a link (or a link id) for kinds whose rules target links (`LinkRules`).
|
|
99
|
+
*
|
|
100
|
+
* For an n-ary kind (`arity: 'n'`), a `target` that is one of its hubs is checked as a new leg
|
|
101
|
+
* of that hub; any other target, as a new link from `source` to `target`.
|
|
92
102
|
*/
|
|
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;
|
|
103
|
+
export declare function canLink<EK extends string = ElementKind, LK extends string = LinkKind>(model: IstarModel<EK, LK>, source: string | IstarElement<EK>, target: string | IstarElement<EK> | IstarLink<LK>, kind: LK, options?: CanLinkOptions<EK, LK>): LinkCheck;
|
|
94
104
|
/**
|
|
95
105
|
* What an extension's `check` predicate receives: the model, the endpoints, and the graph
|
|
96
106
|
* queries the iStar 2.0 rules use.
|
|
@@ -101,9 +111,17 @@ export interface LinkRuleContext {
|
|
|
101
111
|
/** The link kind being added. */
|
|
102
112
|
readonly kind: string;
|
|
103
113
|
readonly source: IstarElement<string>;
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
114
|
+
/** An element, or a link for kinds whose rules target links (narrow with `isLinkRef`). */
|
|
115
|
+
readonly target: IstarElement<string> | IstarLink<string>;
|
|
116
|
+
/**
|
|
117
|
+
* A link (optionally of `kind`, or a kind behaving like it) joins `a` and `b`, either way. Both
|
|
118
|
+
* may be elements or links.
|
|
119
|
+
*/
|
|
120
|
+
isThereLinkBetween(a: {
|
|
121
|
+
readonly id: string;
|
|
122
|
+
}, b: {
|
|
123
|
+
readonly id: string;
|
|
124
|
+
}, kind?: string): boolean;
|
|
107
125
|
/** `element` is the source of a link of `kind` (or a kind behaving like it). */
|
|
108
126
|
isSourceOfType(element: IstarElement<string>, kind: string): boolean;
|
|
109
127
|
/** `element` is the target of a link of `kind` (or a kind behaving like it). */
|
|
@@ -120,7 +138,9 @@ export interface ModelIssue<LK extends string = LinkKind> {
|
|
|
120
138
|
/**
|
|
121
139
|
* Re-validates every link of a model, the way piStar does when loading a file: dependencies
|
|
122
140
|
* first (each checked before its own links are added), then the remaining links in file
|
|
123
|
-
* order, each against the graph built so far
|
|
141
|
+
* order, each against the graph built so far, and last the links that target links. Invalid
|
|
142
|
+
* links are reported, not removed. A hub without an end or legs is reported with code
|
|
143
|
+
* `incomplete-hub`, the hub's id as `linkId` and the n-ary kind as `kind`.
|
|
124
144
|
*/
|
|
125
145
|
export declare function validateModel<EK extends string, LK extends string>(model: IstarModel<EK, LK>, options: CanLinkOptions<EK, LK>): ModelIssue<LK>[];
|
|
126
146
|
export declare function validateModel<EK extends string, LK extends string>(model: IstarModel<EK, LK>): ModelIssue<LK>[];
|
|
@@ -135,6 +155,10 @@ export type ElementCategory = "actor" | "node";
|
|
|
135
155
|
export interface KindShape {
|
|
136
156
|
readonly path: string;
|
|
137
157
|
readonly viewBox?: string;
|
|
158
|
+
/** SVG `stroke-dasharray` of the outline, e.g. `'8,4'` for a dashed shape. */
|
|
159
|
+
readonly dash?: string;
|
|
160
|
+
/** Outline width, when it differs from the renderer's default. */
|
|
161
|
+
readonly strokeWidth?: number;
|
|
138
162
|
}
|
|
139
163
|
export interface KindTextBox {
|
|
140
164
|
readonly top: number;
|
|
@@ -167,15 +191,29 @@ export interface ElementKindDefinition<K extends string = string> {
|
|
|
167
191
|
/** Presentation hints (drawn by `@istar-ts/react`). */
|
|
168
192
|
readonly shape?: KindShape;
|
|
169
193
|
readonly textBox?: KindTextBox;
|
|
194
|
+
/** `hub` for the kind generated for an n-ary link kind's hubs (see `LinkKindDeclaration.arity`). */
|
|
195
|
+
readonly role?: "hub";
|
|
196
|
+
/** For a hub kind: the n-ary link kind it was generated for. */
|
|
197
|
+
readonly of?: string;
|
|
198
|
+
}
|
|
199
|
+
/** The kinds generated for an n-ary link kind: its hub element kind, leg and end link kinds. */
|
|
200
|
+
export interface HubLinkParts {
|
|
201
|
+
readonly hub: string;
|
|
202
|
+
readonly leg: string;
|
|
203
|
+
readonly end: string;
|
|
170
204
|
}
|
|
171
205
|
/**
|
|
172
206
|
* Declarative link rules, as piStar-ext's "Create a new Construct" dialog collects them:
|
|
173
207
|
* which kinds may be the source and target. Entries are kind names (`istar.Goal`,
|
|
174
208
|
* `rationalAgents.Plan`) or categories (`node`, `actor`, `*`). A kind name also matches kinds
|
|
175
209
|
* that behave like it, so `istar.Task` accepts a Planning that behaves like a Task.
|
|
210
|
+
*
|
|
211
|
+
* A link may also target another link (NFR's Argument link points at a Contribution): `targets`
|
|
212
|
+
* then holds `link` (any link) or link kind names. Sources are always elements.
|
|
176
213
|
*/
|
|
177
214
|
export interface LinkRules {
|
|
178
215
|
readonly sources: readonly string[];
|
|
216
|
+
/** Element selectors as for `sources`, plus `link` and link kind names. */
|
|
179
217
|
readonly targets: readonly string[];
|
|
180
218
|
/**
|
|
181
219
|
* Source and target must belong to the same actor (iStar 2.0 Guide, page 14). Default true
|
|
@@ -208,13 +246,44 @@ export interface LinkKindDefinition<K extends string = string> {
|
|
|
208
246
|
readonly extension?: string;
|
|
209
247
|
/** Presentation hint (drawn by `@istar-ts/react`). */
|
|
210
248
|
readonly line?: KindLine;
|
|
249
|
+
/** `'n'` for an n-ary link kind (several sources joined at a hub); absent means 1. */
|
|
250
|
+
readonly arity?: 1 | "n";
|
|
251
|
+
/** For an n-ary kind: the kinds generated for it. */
|
|
252
|
+
readonly parts?: HubLinkParts;
|
|
253
|
+
/** For a generated kind: `leg` (a source → the hub) or `end` (the hub → the target). */
|
|
254
|
+
readonly role?: "leg" | "end";
|
|
255
|
+
/** For a generated kind: the n-ary link kind it was generated for. */
|
|
256
|
+
readonly of?: string;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* How a root metamodel's files look, for models that don't come from a file (`createEmptyModel`)
|
|
260
|
+
* and for writing them (`toPistar`). Files that were read keep their own layout.
|
|
261
|
+
*/
|
|
262
|
+
export interface MetamodelFileHints {
|
|
263
|
+
/** The `tool` a new model records. Default: piStar's `pistar.2.1.0`. */
|
|
264
|
+
readonly tool?: string;
|
|
265
|
+
/** The `istar` version a new model records; only iStar 2.0 sets it (`'2.0'`). */
|
|
266
|
+
readonly istar?: string;
|
|
267
|
+
/** Extra top-level keys of a new model (its `extra`), e.g. `{ metamodelVersion: '1.0' }`. */
|
|
268
|
+
readonly extra?: Readonly<Record<string, unknown>>;
|
|
269
|
+
/** Top-level key order for models without a source layout. Default: piStar's. */
|
|
270
|
+
readonly keys?: readonly string[];
|
|
211
271
|
}
|
|
212
272
|
/** A metamodel: the element and link kinds a model may use, and their rules. */
|
|
213
273
|
export interface Metamodel<EK extends string = ElementKind, LK extends string = LinkKind> {
|
|
214
|
-
/**
|
|
274
|
+
/**
|
|
275
|
+
* The root's name (`istar-2.0`), followed by the names of the extensions applied, e.g.
|
|
276
|
+
* `istar-2.0+rationalAgents`.
|
|
277
|
+
*/
|
|
215
278
|
readonly name: string;
|
|
279
|
+
/** The root metamodel's name, e.g. `istar-2.0`; extensions keep it. */
|
|
280
|
+
readonly framework: string;
|
|
281
|
+
/** The root's namespace (`istar`). Extensions may not declare kinds in it. */
|
|
282
|
+
readonly prefix: string;
|
|
283
|
+
/** How the root's files look (see `MetamodelFileHints`); extensions keep it. */
|
|
284
|
+
readonly file: MetamodelFileHints;
|
|
216
285
|
readonly extensions: readonly string[];
|
|
217
|
-
/** In declaration order:
|
|
286
|
+
/** In declaration order: the root's kinds first, then each extension's. */
|
|
218
287
|
readonly elements: ReadonlyMap<EK, ElementKindDefinition<EK>>;
|
|
219
288
|
readonly links: ReadonlyMap<LK, LinkKindDefinition<LK>>;
|
|
220
289
|
/** `type` in piStar files → kind. */
|
|
@@ -226,8 +295,6 @@ export type ElementKindOf<M> = M extends Metamodel<infer EK, string> ? EK : neve
|
|
|
226
295
|
export type LinkKindOf<M> = M extends Metamodel<string, infer LK> ? LK : never;
|
|
227
296
|
/** A metamodel of any dialect, for code that handles every kind generically. */
|
|
228
297
|
export type AnyMetamodel = Metamodel<string, string>;
|
|
229
|
-
/** iStar 2.0, as the piStar tool implements it. The default metamodel everywhere. */
|
|
230
|
-
export declare const ISTAR_2_0: Metamodel;
|
|
231
298
|
export interface ElementKindDeclaration<K extends string = string> {
|
|
232
299
|
/** Namespaced kind name, e.g. `rationalAgents.Planning`. */
|
|
233
300
|
readonly kind: K;
|
|
@@ -237,7 +304,10 @@ export interface ElementKindDeclaration<K extends string = string> {
|
|
|
237
304
|
readonly category?: ElementCategory;
|
|
238
305
|
/** An existing element kind whose link rules this kind follows, e.g. `istar.Task`. */
|
|
239
306
|
readonly behavesLike?: string;
|
|
240
|
-
/**
|
|
307
|
+
/**
|
|
308
|
+
* Containment rules for nodes. Default: those of `behavesLike`, else piStar-ext's (inner,
|
|
309
|
+
* dependum) in an extension and DSM3's (inner, dependum, on paper) in a root.
|
|
310
|
+
*/
|
|
241
311
|
readonly info?: Partial<NodeKindInfo>;
|
|
242
312
|
/** Default: that of `behavesLike`, else piStar-ext's 90×55 for nodes and 200×120 for actors. */
|
|
243
313
|
readonly size?: Size;
|
|
@@ -257,7 +327,10 @@ export interface LinkKindDeclaration<K extends string = string> {
|
|
|
257
327
|
readonly category?: LinkCategory;
|
|
258
328
|
/** An existing link kind whose rules this kind takes on, e.g. `istar.OrRefinementLink`. */
|
|
259
329
|
readonly behavesLike?: string;
|
|
260
|
-
/**
|
|
330
|
+
/**
|
|
331
|
+
* Declarative rules; give these or `behavesLike`, not both. A root's link kind may give
|
|
332
|
+
* neither when the library has built-in rules for it (iStar 2.0's links).
|
|
333
|
+
*/
|
|
261
334
|
readonly rules?: LinkRules;
|
|
262
335
|
/** An extra predicate, checked after the other rules pass. */
|
|
263
336
|
readonly check?: (context: LinkRuleContext) => LinkCheck;
|
|
@@ -266,6 +339,28 @@ export interface LinkKindDeclaration<K extends string = string> {
|
|
|
266
339
|
readonly pistarType?: string;
|
|
267
340
|
/** Presentation hint, kept as data for renderers (`@istar-ts/react` draws it). */
|
|
268
341
|
readonly line?: KindLine;
|
|
342
|
+
/**
|
|
343
|
+
* `'n'` for a link with several sources, like KAOS's AND-refinement: in a model it is a hub
|
|
344
|
+
* element joined to each source by a leg link and to the target by an end link, as DSM3-goals
|
|
345
|
+
* draws and saves it. Declaring it generates three kinds, named after this one (`parts`):
|
|
346
|
+
* `<kind>Hub`, `<kind>Start` and `<kind>End`, written as `<pistarType>Hub` etc. Needs `rules`
|
|
347
|
+
* and the `node` category.
|
|
348
|
+
*/
|
|
349
|
+
readonly arity?: "n";
|
|
350
|
+
/** Names of the generated kinds, when the defaults don't suit. */
|
|
351
|
+
readonly parts?: Partial<HubLinkParts>;
|
|
352
|
+
/** The hub's size. Default 20×20, as in DSM3-goals. */
|
|
353
|
+
readonly hubSize?: Size;
|
|
354
|
+
}
|
|
355
|
+
/** A whole modelling language, turned into a `Metamodel` by `defineMetamodel`. */
|
|
356
|
+
export interface RootMetamodelDeclaration<EK extends string = string, LK extends string = string> {
|
|
357
|
+
/** Identifies the language; the metamodel's `name` and `framework`, e.g. `istar-2.0`. */
|
|
358
|
+
readonly name: string;
|
|
359
|
+
/** The language's namespace, e.g. `istar`. Extensions may not declare kinds in it. */
|
|
360
|
+
readonly prefix: string;
|
|
361
|
+
readonly elements: readonly ElementKindDeclaration<EK>[];
|
|
362
|
+
readonly links: readonly LinkKindDeclaration<LK>[];
|
|
363
|
+
readonly file?: MetamodelFileHints;
|
|
269
364
|
}
|
|
270
365
|
/** A named set of new kinds, applied to a metamodel with `extendMetamodel`. */
|
|
271
366
|
export interface MetamodelExtension<NEK extends string = string, NLK extends string = string> {
|
|
@@ -282,11 +377,27 @@ export declare class MetamodelError extends Error {
|
|
|
282
377
|
* type the result). Identity at runtime.
|
|
283
378
|
*/
|
|
284
379
|
export declare function defineMetamodelExtension<const NEK extends string = never, const NLK extends string = never>(extension: MetamodelExtension<NEK, NLK>): MetamodelExtension<NEK, NLK>;
|
|
380
|
+
/** The `targets` selector for any link (see `LinkRules`). */
|
|
381
|
+
export declare const LINK_SELECTOR = "link";
|
|
285
382
|
/**
|
|
286
|
-
*
|
|
383
|
+
* Builds a root metamodel: a modelling language of its own, such as iStar 2.0, KAOS or NFR.
|
|
384
|
+
* Kinds are namespaced (any namespace; usually `prefix`), declared in order: `behavesLike` and
|
|
385
|
+
* link rules refer to kinds declared before them. Extensions of the result may not use `prefix`.
|
|
287
386
|
*
|
|
288
|
-
* Throws `MetamodelError`
|
|
289
|
-
|
|
387
|
+
* Throws `MetamodelError` on the same declaration errors as `extendMetamodel`.
|
|
388
|
+
*/
|
|
389
|
+
export declare function defineMetamodel<const EK extends string, const LK extends string>(declaration: RootMetamodelDeclaration<EK, LK>): Metamodel<EK, LK>;
|
|
390
|
+
/** iStar 2.0's declaration, built from the constants in `metamodel.ts`. */
|
|
391
|
+
export declare const ISTAR_2_0_DECLARATION: RootMetamodelDeclaration<ElementKind, LinkKind>;
|
|
392
|
+
/** iStar 2.0, as the piStar tool implements it. The default metamodel everywhere. */
|
|
393
|
+
export declare const ISTAR_2_0: Metamodel;
|
|
394
|
+
/**
|
|
395
|
+
* Returns a new metamodel with the extension's kinds added. `base` is not modified. The result
|
|
396
|
+
* keeps `base`'s `framework`, `prefix` and `file`.
|
|
397
|
+
*
|
|
398
|
+
* Throws `MetamodelError` when a kind name isn't namespaced, uses the root's reserved prefix
|
|
399
|
+
* (`istar.` for iStar 2.0), collides with an existing kind or piStar type, or refers to an
|
|
400
|
+
* unknown kind.
|
|
290
401
|
*/
|
|
291
402
|
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>;
|
|
292
403
|
export declare function elementKindDefinition(metamodel: AnyMetamodel, kind: string): ElementKindDefinition | undefined;
|
|
@@ -302,6 +413,10 @@ export declare function isNodeKindIn(metamodel: AnyMetamodel, kind: string): boo
|
|
|
302
413
|
export declare function effectiveElementKind(metamodel: AnyMetamodel, kind: string): string;
|
|
303
414
|
/** Like `effectiveElementKind`, for link kinds. */
|
|
304
415
|
export declare function effectiveLinkKind(metamodel: AnyMetamodel, kind: string): string;
|
|
416
|
+
/** True when link `kind` is `ancestor` or (transitively) behaves like it. */
|
|
417
|
+
export declare function linkBehavesLike(metamodel: AnyMetamodel, kind: string, ancestor: string): boolean;
|
|
418
|
+
/** True when a link kind's rules let it target links (`link` or a link kind in `targets`). */
|
|
419
|
+
export declare function targetsLinks(metamodel: AnyMetamodel, kind: string): boolean;
|
|
305
420
|
/** True when `kind` is `ancestor` or (transitively) behaves like it. */
|
|
306
421
|
export declare function elementBehavesLike(metamodel: AnyMetamodel, kind: string, ancestor: string): boolean;
|
|
307
422
|
//#endregion
|
|
@@ -401,6 +516,13 @@ export interface IstarModel<EK extends string = ElementKind, LK extends string =
|
|
|
401
516
|
/** Tool identifier written by piStar 2.1.0, whose file format this library emulates. */
|
|
402
517
|
export declare const PISTAR_TOOL = "pistar.2.1.0";
|
|
403
518
|
export declare const ISTAR_VERSION = "2.0";
|
|
519
|
+
/**
|
|
520
|
+
* DSM3-goals' file conventions, shared by its languages (KAOS, NFR; see `@istar-ts/dsm3-kaos`
|
|
521
|
+
* and `@istar-ts/dsm3-nfr`): the `tool` its editors write, and the order of their top-level keys
|
|
522
|
+
* (`fileManager.js`). Use them as a root's `file.tool` and `file.keys`.
|
|
523
|
+
*/
|
|
524
|
+
export declare const DSM3_TOOL = "dsm3-goals";
|
|
525
|
+
export declare const DSM3_FILE_KEYS: readonly string[];
|
|
404
526
|
export declare const DEFAULT_DIAGRAM: Diagram;
|
|
405
527
|
/** A model of any dialect, for code that handles every kind generically. */
|
|
406
528
|
export type AnyIstarModel = IstarModel<string, string>;
|
|
@@ -441,13 +563,38 @@ export declare function isActorIn(metamodel: AnyMetamodel): (element: IstarEleme
|
|
|
441
563
|
export declare function isNodeIn(metamodel: AnyMetamodel): (element: IstarElement<string> | undefined) => boolean;
|
|
442
564
|
/** Inner elements of an actor, in model order. */
|
|
443
565
|
export declare function childrenOf<EK extends string, LK extends string>(model: IstarModel<EK, LK>, actorId: string): IstarElement<EK>[];
|
|
444
|
-
/**
|
|
566
|
+
/**
|
|
567
|
+
* Links that have the element as source or target. Given a link id, the links that target that
|
|
568
|
+
* link (see `LinkRules`).
|
|
569
|
+
*/
|
|
445
570
|
export declare function linksOf<EK extends string, LK extends string>(model: IstarModel<EK, LK>, elementId: string): IstarLink<LK>[];
|
|
446
571
|
/** For a dependum, the two halves of its dependency: depender → dependum → dependee. */
|
|
447
572
|
export declare function dependencyLinksOf<EK extends string, LK extends string>(model: IstarModel<EK, LK>, dependumId: string): {
|
|
448
573
|
inbound?: IstarLink<LK>;
|
|
449
574
|
outbound?: IstarLink<LK>;
|
|
450
575
|
};
|
|
576
|
+
/** What a link points at: an element, or a link for kinds whose rules target links. */
|
|
577
|
+
export declare function linkTargetOf<EK extends string, LK extends string>(model: IstarModel<EK, LK>, link: IstarLink<LK>): IstarElement<EK> | IstarLink<LK> | undefined;
|
|
578
|
+
/** An n-ary link as it lives in a model: its hub element, its legs (in link order), its end. */
|
|
579
|
+
export interface HubLink<EK extends string = ElementKind, LK extends string = LinkKind> {
|
|
580
|
+
readonly hub: IstarElement<EK>;
|
|
581
|
+
readonly legs: readonly IstarLink<LK>[];
|
|
582
|
+
/** Absent only in an incomplete model (`validateModel` reports it). */
|
|
583
|
+
readonly end?: IstarLink<LK>;
|
|
584
|
+
}
|
|
585
|
+
/** True when `element` is the hub of an n-ary link. */
|
|
586
|
+
export declare function isHubElement(metamodel: AnyMetamodel, element: IstarElement<string> | undefined): boolean;
|
|
587
|
+
/** The n-ary link whose hub is `hubId`; `undefined` when it isn't a hub. */
|
|
588
|
+
export declare function hubLinkOf<EK extends string, LK extends string>(model: IstarModel<EK, LK>, hubId: string): HubLink<EK, LK> | undefined;
|
|
589
|
+
/** The hub a leg or end link belongs to. */
|
|
590
|
+
export declare function hubOfLink<EK extends string, LK extends string>(model: IstarModel<EK, LK>, linkId: string): IstarElement<EK> | undefined;
|
|
591
|
+
/** The centre of an element's box: its display size, else its kind's default size. */
|
|
592
|
+
export declare function elementCenter<EK extends string, LK extends string>(model: IstarModel<EK, LK>, element: IstarElement<EK>): Point;
|
|
593
|
+
/**
|
|
594
|
+
* Where a new hub goes: centred between the source and the target, as DSM3-goals places it.
|
|
595
|
+
* Returns its top-left corner for a hub of `size`.
|
|
596
|
+
*/
|
|
597
|
+
export declare function defaultHubPosition<EK extends string, LK extends string>(model: IstarModel<EK, LK>, source: IstarElement<EK>, target: IstarElement<EK>, size: Size): Point;
|
|
451
598
|
//#endregion
|
|
452
599
|
//#region src/file-metamodel.d.ts
|
|
453
600
|
/** The top-level key of the block in piStar JSON. */
|
|
@@ -508,6 +655,30 @@ export interface PistarLinkJson {
|
|
|
508
655
|
label?: string;
|
|
509
656
|
[key: string]: unknown;
|
|
510
657
|
}
|
|
658
|
+
/** The hub of an n-ary link, in a hub entry: an element without `text`. */
|
|
659
|
+
export interface PistarHubJson {
|
|
660
|
+
id: string;
|
|
661
|
+
type: string;
|
|
662
|
+
x: number;
|
|
663
|
+
y: number;
|
|
664
|
+
customProperties?: Record<string, string>;
|
|
665
|
+
[key: string]: unknown;
|
|
666
|
+
}
|
|
667
|
+
/**
|
|
668
|
+
* An n-ary link (see `LinkKindDeclaration.arity`) in `links`, as DSM3-goals writes it: no id of
|
|
669
|
+
* its own, its hub, its legs (`starts`) and its end.
|
|
670
|
+
*/
|
|
671
|
+
export interface PistarHubLinkJson {
|
|
672
|
+
hub: PistarHubJson;
|
|
673
|
+
starts: PistarLinkJson[];
|
|
674
|
+
end?: PistarLinkJson;
|
|
675
|
+
[key: string]: unknown;
|
|
676
|
+
}
|
|
677
|
+
/**
|
|
678
|
+
* Key of a hub element's `extra` that holds its entry's unknown keys (those beside `hub`,
|
|
679
|
+
* `starts` and `end`), so they are written back on the entry.
|
|
680
|
+
*/
|
|
681
|
+
export declare const HUB_ENTRY_KEY = "__hubEntry";
|
|
511
682
|
export interface PistarDiagramJson {
|
|
512
683
|
width?: number;
|
|
513
684
|
height?: number;
|
|
@@ -520,7 +691,7 @@ export interface PistarFile {
|
|
|
520
691
|
actors: PistarActorJson[];
|
|
521
692
|
orphans?: PistarElementJson[];
|
|
522
693
|
dependencies?: PistarDependencyJson[];
|
|
523
|
-
links?: PistarLinkJson[];
|
|
694
|
+
links?: (PistarLinkJson | PistarHubLinkJson)[];
|
|
524
695
|
display?: Record<string, Record<string, unknown>>;
|
|
525
696
|
tool?: string;
|
|
526
697
|
istar?: string;
|
|
@@ -579,6 +750,18 @@ export declare function parsePistar<EK extends string, LK extends string>(input:
|
|
|
579
750
|
}): IstarModel<EK, LK>;
|
|
580
751
|
export declare function parsePistar(input: string | PistarFile | Record<string, unknown>, options: ParsePistarOptions): IstarModel;
|
|
581
752
|
export declare function parsePistar(input: string | PistarFile | Record<string, unknown>): IstarModel;
|
|
753
|
+
/**
|
|
754
|
+
* The namespace of the first `type` in a file (`kaos` for `kaos.Softgoal`), looking at actors and
|
|
755
|
+
* their nodes, orphans, dependencies, then links (hub entries included). `undefined` when no
|
|
756
|
+
* element or link has a namespaced type. Throws `PistarParseError` for a string that isn't JSON.
|
|
757
|
+
*/
|
|
758
|
+
export declare function detectPrefix(json: string | Record<string, unknown>): string | undefined;
|
|
759
|
+
/**
|
|
760
|
+
* Which of `roots` a file is written in: the one whose `prefix` is the file's (`detectPrefix`);
|
|
761
|
+
* for a file without types, the only one whose `file.tool` is the file's `tool`; otherwise
|
|
762
|
+
* `undefined`. Pass the result to `parsePistar(json, { metamodel })`.
|
|
763
|
+
*/
|
|
764
|
+
export declare function detectFramework(json: string | Record<string, unknown>, roots: readonly AnyMetamodel[]): AnyMetamodel | undefined;
|
|
582
765
|
export interface ToPistarOptions {
|
|
583
766
|
/** Default: the model's metamodel, or iStar 2.0. Decides each kind's `type` and category. */
|
|
584
767
|
metamodel?: AnyMetamodel;
|
|
@@ -607,7 +790,7 @@ export declare function fileMetamodelOf<EK extends string, LK extends string>(mo
|
|
|
607
790
|
*/
|
|
608
791
|
export declare function withFileMetamodel<EK extends string, LK extends string>(model: IstarModel<EK, LK>, block: FileMetamodel | null): IstarModel<string, string>;
|
|
609
792
|
declare namespace operations_d_exports {
|
|
610
|
-
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 };
|
|
793
|
+
export { AddDependencyResult, ConnectOptions, ConnectResult, ElementPatch, IdGenerator, LinkPatch, ModelOperationError, NewDependency, NewElement, NewLink, OperationContext, addDependency, addElement, addLeg, connect, defaultIdGenerator, dependencyEnds, disconnect, moveElement, nestElement, removeElement, removeElements, removeLeg, updateDiagram, updateElement, updateLink };
|
|
611
794
|
}
|
|
612
795
|
export declare class ModelOperationError extends Error {
|
|
613
796
|
override name: string;
|
|
@@ -657,7 +840,8 @@ export declare function moveElement<EK extends string = ElementKind, LK extends
|
|
|
657
840
|
export declare function nestElement<EK extends string = ElementKind, LK extends string = LinkKind>(model: IstarModel<EK, LK>, id: string, parent: string | null): IstarModel<EK, LK>;
|
|
658
841
|
/**
|
|
659
842
|
* Removes elements and everything that depends on them: inner elements of removed actors,
|
|
660
|
-
* links touching removed elements, and the rest of any
|
|
843
|
+
* links touching removed elements (and links targeting removed links), and the rest of any
|
|
844
|
+
* dependency that loses a part.
|
|
661
845
|
*/
|
|
662
846
|
export declare function removeElements<EK extends string = ElementKind, LK extends string = LinkKind>(model: IstarModel<EK, LK>, ids: Iterable<string>): IstarModel<EK, LK>;
|
|
663
847
|
export declare function removeElement<EK extends string = ElementKind, LK extends string = LinkKind>(model: IstarModel<EK, LK>, id: string): IstarModel<EK, LK>;
|
|
@@ -665,6 +849,7 @@ export interface NewLink<K extends string = LinkKind> {
|
|
|
665
849
|
/** Any link kind except dependency kinds (use `addDependency` for those). */
|
|
666
850
|
readonly kind: Exclude<K, DependencyLinkKind>;
|
|
667
851
|
readonly source: string;
|
|
852
|
+
/** An element id, or a link id for kinds whose rules target links. */
|
|
668
853
|
readonly target: string;
|
|
669
854
|
readonly id?: string;
|
|
670
855
|
/** Contribution value: make, help, hurt or break. */
|
|
@@ -684,13 +869,35 @@ export interface ConnectOptions extends OperationContext {
|
|
|
684
869
|
export type ConnectResult<EK extends string = ElementKind, LK extends string = LinkKind> = {
|
|
685
870
|
ok: true;
|
|
686
871
|
model: IstarModel<EK, LK>;
|
|
872
|
+
/** The new link; for an n-ary kind, the new leg or (for a new hub) the end. */
|
|
687
873
|
link: IstarLink<LK>;
|
|
688
874
|
reversed: boolean;
|
|
875
|
+
/** For an n-ary kind: the hub link the new link belongs to, as it now is. */
|
|
876
|
+
hub?: HubLink<EK, LK>;
|
|
689
877
|
} | Extract<LinkCheck, {
|
|
690
878
|
ok: false;
|
|
691
879
|
}>;
|
|
692
|
-
/**
|
|
880
|
+
/**
|
|
881
|
+
* Adds a link between two elements if the iStar constraints allow it.
|
|
882
|
+
*
|
|
883
|
+
* With an n-ary kind (`arity: 'n'`), a `target` that is one of the kind's hubs gets a new leg
|
|
884
|
+
* from `source` (see `addLeg`). Any other target gets a new hub, centred between source and
|
|
885
|
+
* target, with a leg from `source` and an end to `target`. `input.id` and `customProperties`
|
|
886
|
+
* then go to the hub, and `label` and `name` to the end.
|
|
887
|
+
*/
|
|
693
888
|
export declare function connect<EK extends string = ElementKind, LK extends string = LinkKind>(model: IstarModel<EK, LK>, input: NewLink<LK>, options?: ConnectOptions): ConnectResult<EK, LK>;
|
|
889
|
+
/**
|
|
890
|
+
* Adds a leg from `source` to the hub `hubId` of an n-ary link (one more source for it), if the
|
|
891
|
+
* kind's rules allow it. `options.id` is the leg's id.
|
|
892
|
+
*/
|
|
893
|
+
export declare function addLeg<EK extends string = ElementKind, LK extends string = LinkKind>(model: IstarModel<EK, LK>, hubId: string, source: string, options?: ConnectOptions & {
|
|
894
|
+
readonly id?: string;
|
|
895
|
+
}): ConnectResult<EK, LK>;
|
|
896
|
+
/**
|
|
897
|
+
* Removes one leg of an n-ary link. Removing its last leg removes the whole link (hub and end),
|
|
898
|
+
* as `disconnect` does.
|
|
899
|
+
*/
|
|
900
|
+
export declare function removeLeg<EK extends string = ElementKind, LK extends string = LinkKind>(model: IstarModel<EK, LK>, legId: string): IstarModel<EK, LK>;
|
|
694
901
|
export interface NewDependency<EK extends string = ElementKind, LK extends string = LinkKind> {
|
|
695
902
|
/** The depender: an actor or one of its inner elements. */
|
|
696
903
|
readonly depender: string;
|
|
@@ -720,7 +927,10 @@ export type AddDependencyResult<EK extends string = ElementKind, LK extends stri
|
|
|
720
927
|
}>;
|
|
721
928
|
/** Adds depender → dependum → dependee. */
|
|
722
929
|
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>;
|
|
723
|
-
/**
|
|
930
|
+
/**
|
|
931
|
+
* Removes a link, and the links that target it. Removing either half of a dependency removes
|
|
932
|
+
* the whole dependency.
|
|
933
|
+
*/
|
|
724
934
|
export declare function disconnect<EK extends string = ElementKind, LK extends string = LinkKind>(model: IstarModel<EK, LK>, id: string): IstarModel<EK, LK>;
|
|
725
935
|
export interface LinkPatch {
|
|
726
936
|
/** `null` removes it. */
|
|
@@ -763,6 +973,10 @@ export type ModelChange = {
|
|
|
763
973
|
} | {
|
|
764
974
|
type: "connect";
|
|
765
975
|
id: string;
|
|
976
|
+
hubId?: string;
|
|
977
|
+
} | {
|
|
978
|
+
type: "removeLeg";
|
|
979
|
+
id: string;
|
|
766
980
|
} | {
|
|
767
981
|
type: "addDependency";
|
|
768
982
|
dependumId: string;
|
|
@@ -802,7 +1016,7 @@ export interface ModelStore<EK extends string = ElementKind, LK extends string =
|
|
|
802
1016
|
getModel(): IstarModel<EK, LK>;
|
|
803
1017
|
/** Returns an unsubscribe function. */
|
|
804
1018
|
subscribe(listener: ModelListener<EK, LK>): () => void;
|
|
805
|
-
canLink(source: string | IstarElement<EK>, target: string | IstarElement<EK>, kind: LK): LinkCheck;
|
|
1019
|
+
canLink(source: string | IstarElement<EK>, target: string | IstarElement<EK> | IstarLink<LK>, kind: LK): LinkCheck;
|
|
806
1020
|
addElement(input: NewElement<EK>): IstarElement<EK>;
|
|
807
1021
|
updateElement(id: string, patch: ElementPatch): void;
|
|
808
1022
|
moveElement(id: string, x: number, y: number): void;
|
|
@@ -812,6 +1026,12 @@ export interface ModelStore<EK extends string = ElementKind, LK extends string =
|
|
|
812
1026
|
setCollapsed(actorId: string, collapsed: boolean): void;
|
|
813
1027
|
connect(input: NewLink<LK>, options?: Omit<ConnectOptions, "createId">): ConnectResult<EK, LK>;
|
|
814
1028
|
addDependency(input: NewDependency<EK, LK>, options?: Omit<ConnectOptions, "createId" | "tryReversed">): AddDependencyResult<EK, LK>;
|
|
1029
|
+
/** Adds a leg from `source` to the hub of an n-ary link (see `ops.addLeg`). */
|
|
1030
|
+
addLeg(hubId: string, source: string, options?: Omit<ConnectOptions, "createId" | "tryReversed"> & {
|
|
1031
|
+
readonly id?: string;
|
|
1032
|
+
}): ConnectResult<EK, LK>;
|
|
1033
|
+
/** Removes a leg; the last one takes its hub and end with it. */
|
|
1034
|
+
removeLeg(id: string): void;
|
|
815
1035
|
updateLink(id: string, patch: LinkPatch): void;
|
|
816
1036
|
disconnect(id: string): void;
|
|
817
1037
|
updateDiagram(patch: Partial<Diagram>): void;
|
|
@@ -908,4 +1128,137 @@ export declare function defineProperties<const S extends PropertyShape, const Ki
|
|
|
908
1128
|
}): PropertySchema<S, Kind>;
|
|
909
1129
|
export declare function validateModelProperties<EK extends string, LK extends string>(model: IstarModel<EK, LK>, schemas: readonly PropertySchema<PropertyShape, string>[]): ModelPropertyIssue[];
|
|
910
1130
|
//#endregion
|
|
1131
|
+
//#region src/diagnostics.d.ts
|
|
1132
|
+
/**
|
|
1133
|
+
* The Goal Model Diagnostics Protocol: findings about a model's elements and links, published by
|
|
1134
|
+
* any analyser (a language server, a validator, a simulation…) and anchored by element id rather
|
|
1135
|
+
* than by text position. Data only: diagnostics are never part of the model and are never
|
|
1136
|
+
* written to disk.
|
|
1137
|
+
*
|
|
1138
|
+
* See goal-controller issue #24 (option D). Producers publish per source; consumers see the
|
|
1139
|
+
* union of every source, deduplicated by `(elementId, key, message)`.
|
|
1140
|
+
*/
|
|
1141
|
+
export type DiagnosticSeverity = "error" | "warning" | "info" | "hint";
|
|
1142
|
+
/** Most severe first. */
|
|
1143
|
+
export declare const DIAGNOSTIC_SEVERITIES: readonly DiagnosticSeverity[];
|
|
1144
|
+
/** A zero-based position in the producer's document (as in LSP). */
|
|
1145
|
+
export interface DiagnosticPosition {
|
|
1146
|
+
readonly line: number;
|
|
1147
|
+
readonly character: number;
|
|
1148
|
+
}
|
|
1149
|
+
export interface DiagnosticRange {
|
|
1150
|
+
readonly start: DiagnosticPosition;
|
|
1151
|
+
readonly end: DiagnosticPosition;
|
|
1152
|
+
}
|
|
1153
|
+
export interface GoalDiagnostic {
|
|
1154
|
+
/** Id of the element or link the diagnostic is about. */
|
|
1155
|
+
readonly elementId: string;
|
|
1156
|
+
/** The custom property it is about; absent for the element as a whole. */
|
|
1157
|
+
readonly key?: string;
|
|
1158
|
+
readonly severity: DiagnosticSeverity;
|
|
1159
|
+
readonly message: string;
|
|
1160
|
+
/** Who published it (e.g. `mutrose`, `goal-language`). */
|
|
1161
|
+
readonly source?: string;
|
|
1162
|
+
/** Where it was found in the producer's document, if it has one. */
|
|
1163
|
+
readonly range?: DiagnosticRange;
|
|
1164
|
+
readonly code?: string;
|
|
1165
|
+
/** Producer data, passed through untouched. */
|
|
1166
|
+
readonly data?: unknown;
|
|
1167
|
+
}
|
|
1168
|
+
/** Negative when `a` is more severe than `b`. */
|
|
1169
|
+
export declare function compareSeverity(a: DiagnosticSeverity, b: DiagnosticSeverity): number;
|
|
1170
|
+
/** The most severe severity in a list (what a badge shows), or `undefined` if it is empty. */
|
|
1171
|
+
export declare function worstDiagnosticSeverity(diagnostics: readonly {
|
|
1172
|
+
readonly severity: DiagnosticSeverity;
|
|
1173
|
+
}[] | undefined): DiagnosticSeverity | undefined;
|
|
1174
|
+
/**
|
|
1175
|
+
* The union of several lists, in order, without duplicates: diagnostics with the same
|
|
1176
|
+
* `(elementId, key, message)` count once, keeping the first one's position and the most severe
|
|
1177
|
+
* severity among them.
|
|
1178
|
+
*/
|
|
1179
|
+
export declare function mergeDiagnostics(lists: Iterable<readonly GoalDiagnostic[] | undefined>): GoalDiagnostic[];
|
|
1180
|
+
/** Diagnostics by element (or link) id, each list in the input order. */
|
|
1181
|
+
export declare function groupDiagnostics(diagnostics: readonly GoalDiagnostic[] | undefined): ReadonlyMap<string, readonly GoalDiagnostic[]>;
|
|
1182
|
+
/**
|
|
1183
|
+
* Holds the diagnostics of several sources. Each `publish` replaces that source's set, so a
|
|
1184
|
+
* producer re-publishes everything it currently reports, as an LSP server does.
|
|
1185
|
+
*/
|
|
1186
|
+
export interface DiagnosticsStore {
|
|
1187
|
+
/**
|
|
1188
|
+
* Replaces `source`'s diagnostics (an empty list clears them). Entries without a `source` get
|
|
1189
|
+
* this one.
|
|
1190
|
+
*/
|
|
1191
|
+
publish(source: string, diagnostics: readonly GoalDiagnostic[]): void;
|
|
1192
|
+
/** Removes one source's diagnostics, or every source's. */
|
|
1193
|
+
clear(source?: string): void;
|
|
1194
|
+
/** Sources with diagnostics, in the order they first published. */
|
|
1195
|
+
sources(): readonly string[];
|
|
1196
|
+
/** One source's diagnostics. */
|
|
1197
|
+
get(source: string): readonly GoalDiagnostic[];
|
|
1198
|
+
/**
|
|
1199
|
+
* Every source's diagnostics, merged (see `mergeDiagnostics`). The same array until the next
|
|
1200
|
+
* change, so it can back `useSyncExternalStore`.
|
|
1201
|
+
*/
|
|
1202
|
+
getAll(): readonly GoalDiagnostic[];
|
|
1203
|
+
subscribe(listener: () => void): () => void;
|
|
1204
|
+
}
|
|
1205
|
+
export declare function createDiagnosticsStore(): DiagnosticsStore;
|
|
1206
|
+
/**
|
|
1207
|
+
* The parts of an LSP `Diagnostic` the adapter reads (structurally typed, so no LSP library is
|
|
1208
|
+
* needed). The element is taken from `data.elementId`, or MutRoSe's `data.nodeId`; the property
|
|
1209
|
+
* from `data.key`.
|
|
1210
|
+
*/
|
|
1211
|
+
export interface LspDiagnosticLike {
|
|
1212
|
+
readonly range?: DiagnosticRange;
|
|
1213
|
+
/** LSP numbering: 1 error, 2 warning, 3 information, 4 hint. */
|
|
1214
|
+
readonly severity?: number;
|
|
1215
|
+
readonly message: string | {
|
|
1216
|
+
readonly value: string;
|
|
1217
|
+
};
|
|
1218
|
+
readonly source?: string;
|
|
1219
|
+
readonly code?: string | number | {
|
|
1220
|
+
readonly value: string | number;
|
|
1221
|
+
};
|
|
1222
|
+
readonly data?: unknown;
|
|
1223
|
+
}
|
|
1224
|
+
export interface FromLspOptions<D extends LspDiagnosticLike = LspDiagnosticLike> {
|
|
1225
|
+
/**
|
|
1226
|
+
* The element of a diagnostic whose `data` names none, e.g. by looking its range up in the
|
|
1227
|
+
* document. Return `undefined` to drop it.
|
|
1228
|
+
*/
|
|
1229
|
+
readonly elementIdFor?: (diagnostic: D) => string | undefined;
|
|
1230
|
+
/**
|
|
1231
|
+
* `'vscode'` for `vscode.Diagnostic` objects, whose severity counts from 0 (error) to 3
|
|
1232
|
+
* (hint). Default `'lsp'`, the protocol's 1 to 4.
|
|
1233
|
+
*/
|
|
1234
|
+
readonly severityNumbering?: "lsp" | "vscode";
|
|
1235
|
+
}
|
|
1236
|
+
/**
|
|
1237
|
+
* One LSP diagnostic anchored by `data.elementId` (or `data.nodeId`), or `undefined` when it
|
|
1238
|
+
* names no element. For range-anchored diagnostics use `fromLspDiagnostics` with `elementIdFor`.
|
|
1239
|
+
*/
|
|
1240
|
+
export declare function fromLspDiagnostic(diagnostic: LspDiagnosticLike): GoalDiagnostic | undefined;
|
|
1241
|
+
/** LSP diagnostics as goal diagnostics; those that can't be anchored to an element are dropped. */
|
|
1242
|
+
export declare function fromLspDiagnostics<D extends LspDiagnosticLike>(diagnostics: readonly D[], options?: FromLspOptions<D>): GoalDiagnostic[];
|
|
1243
|
+
/**
|
|
1244
|
+
* The shape MutRoSe's VS Code extension posts to its webview: `{ nodeId, severity, message }`
|
|
1245
|
+
* (plus `range` and `source`). `nodeId` is missing when no node could be found.
|
|
1246
|
+
*/
|
|
1247
|
+
export interface NodeIdDiagnostic {
|
|
1248
|
+
readonly nodeId?: string;
|
|
1249
|
+
readonly key?: string;
|
|
1250
|
+
readonly severity: DiagnosticSeverity | string;
|
|
1251
|
+
readonly message: string;
|
|
1252
|
+
readonly source?: string;
|
|
1253
|
+
readonly range?: DiagnosticRange;
|
|
1254
|
+
readonly code?: string;
|
|
1255
|
+
}
|
|
1256
|
+
/** One `{ nodeId, severity, message }` diagnostic, or `undefined` without a `nodeId`. */
|
|
1257
|
+
export declare function fromNodeIdDiagnostic(diagnostic: NodeIdDiagnostic): GoalDiagnostic | undefined;
|
|
1258
|
+
/**
|
|
1259
|
+
* `{ nodeId, severity, message }` diagnostics (MutRoSe) as goal diagnostics, dropping those
|
|
1260
|
+
* without a node: `store.publish('mutrose', fromNodeIdDiagnostics(message.diagnostics))`.
|
|
1261
|
+
*/
|
|
1262
|
+
export declare function fromNodeIdDiagnostics(diagnostics: readonly NodeIdDiagnostic[]): GoalDiagnostic[];
|
|
1263
|
+
//#endregion
|
|
911
1264
|
//# sourceMappingURL=index.d.ts.map
|