@istar-ts/core 0.10.1 → 0.12.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/dist/index.d.cts CHANGED
@@ -128,6 +128,25 @@ export declare function validateModel(model: IstarModel): ModelIssue[];
128
128
  //#endregion
129
129
  //#region src/metamodels.d.ts
130
130
  export type ElementCategory = "actor" | "node";
131
+ /**
132
+ * Presentation hints a kind may carry, as data (core never draws). `@istar-ts/react` uses them as
133
+ * the defaults for the kind: a shape as SVG path data, the label's text box, a link's line.
134
+ */
135
+ export interface KindShape {
136
+ readonly path: string;
137
+ readonly viewBox?: string;
138
+ }
139
+ export interface KindTextBox {
140
+ readonly top: number;
141
+ readonly right: number;
142
+ readonly bottom: number;
143
+ readonly left: number;
144
+ }
145
+ export interface KindLine {
146
+ readonly dash?: string;
147
+ readonly marker?: string | false;
148
+ readonly markerFilled?: boolean;
149
+ }
131
150
  export type LinkCategory = "actor" | "node" | "dependency";
132
151
  /** A resolved element kind of a metamodel. */
133
152
  export interface ElementKindDefinition<K extends string = string> {
@@ -145,6 +164,9 @@ export interface ElementKindDefinition<K extends string = string> {
145
164
  readonly pistarType: string;
146
165
  /** Name of the extension that declared it; absent for iStar 2.0 kinds. */
147
166
  readonly extension?: string;
167
+ /** Presentation hints (drawn by `@istar-ts/react`). */
168
+ readonly shape?: KindShape;
169
+ readonly textBox?: KindTextBox;
148
170
  }
149
171
  /**
150
172
  * Declarative link rules, as piStar-ext's "Create a new Construct" dialog collects them:
@@ -184,6 +206,8 @@ export interface LinkKindDefinition<K extends string = string> {
184
206
  readonly check?: (context: LinkRuleContext) => LinkCheck;
185
207
  readonly pistarType: string;
186
208
  readonly extension?: string;
209
+ /** Presentation hint (drawn by `@istar-ts/react`). */
210
+ readonly line?: KindLine;
187
211
  }
188
212
  /** A metamodel: the element and link kinds a model may use, and their rules. */
189
213
  export interface Metamodel<EK extends string = ElementKind, LK extends string = LinkKind> {
@@ -222,6 +246,9 @@ export interface ElementKindDeclaration<K extends string = string> {
222
246
  * constructs as `istar.<Name>`, so `pistarType: 'istar.Planning'` reads its files.
223
247
  */
224
248
  readonly pistarType?: string;
249
+ /** Presentation hints, kept as data for renderers (`@istar-ts/react` draws them). */
250
+ readonly shape?: KindShape;
251
+ readonly textBox?: KindTextBox;
225
252
  }
226
253
  export interface LinkKindDeclaration<K extends string = string> {
227
254
  readonly kind: K;
@@ -237,6 +264,8 @@ export interface LinkKindDeclaration<K extends string = string> {
237
264
  /** Default: that of `behavesLike`, else none (no fixed label, no changeable value). */
238
265
  readonly info?: LinkKindInfo;
239
266
  readonly pistarType?: string;
267
+ /** Presentation hint, kept as data for renderers (`@istar-ts/react` draws it). */
268
+ readonly line?: KindLine;
240
269
  }
241
270
  /** A named set of new kinds, applied to a metamodel with `extendMetamodel`. */
242
271
  export interface MetamodelExtension<NEK extends string = string, NLK extends string = string> {
@@ -381,6 +410,10 @@ export type AnyIstarModel = IstarModel<string, string>;
381
410
  * the association.
382
411
  */
383
412
  export declare function withMetamodel<EK extends string, LK extends string>(model: IstarModel<string, string>, metamodel: Metamodel<EK, LK>): IstarModel<EK, LK>;
413
+ /** @internal Records the host part of a model's metamodel (used by serialization). */
414
+ export declare function setHostMetamodel(model: object, metamodel: AnyMetamodel | undefined): void;
415
+ /** @internal The host part of a model's metamodel, if the file declares the rest. */
416
+ export declare function hostMetamodelOf(model: object): AnyMetamodel | undefined;
384
417
  /** Gives `to` the metamodel of `from` (used for every model an operation derives). */
385
418
  export declare function inheritMetamodel<M extends IstarModel<string, string>>(from: IstarModel<string, string>, to: M): M;
386
419
  export declare function createEmptyModel<EK extends string, LK extends string>(diagram: Diagram | undefined, options: {
@@ -416,6 +449,38 @@ export declare function dependencyLinksOf<EK extends string, LK extends string>(
416
449
  outbound?: IstarLink<LK>;
417
450
  };
418
451
  //#endregion
452
+ //#region src/file-metamodel.d.ts
453
+ /** The top-level key of the block in piStar JSON. */
454
+ export declare const FILE_METAMODEL_KEY = "metamodel";
455
+ export interface FileElementKind extends Omit<ElementKindDeclaration<string>, "info"> {
456
+ readonly info?: {
457
+ readonly canBeInnerElement?: boolean;
458
+ readonly canBeDependum?: boolean;
459
+ readonly canBeOnPaper?: boolean;
460
+ };
461
+ readonly [key: string]: unknown;
462
+ }
463
+ export interface FileLinkKind extends Omit<LinkKindDeclaration<string>, "check"> {
464
+ readonly [key: string]: unknown;
465
+ }
466
+ /** The `"metamodel"` block of a model file. */
467
+ export interface FileMetamodel {
468
+ /** Identifies the constructs' dialect, e.g. `iStar4RationalAgents`. */
469
+ readonly name: string;
470
+ readonly elements?: readonly FileElementKind[];
471
+ readonly links?: readonly FileLinkKind[];
472
+ readonly [key: string]: unknown;
473
+ }
474
+ /**
475
+ * Checks that `value` is a well-formed `"metamodel"` block and returns it typed. Throws
476
+ * `MetamodelError` naming the offending path (`metamodel.elements[1].kind must be a string`).
477
+ * Whether its kinds fit a given metamodel (namespacing, collisions, `behavesLike` targets) is
478
+ * checked when it is applied, by `extendMetamodel`.
479
+ */
480
+ export declare function validateFileMetamodel(value: unknown, path?: string): FileMetamodel;
481
+ /** The block as an extension `extendMetamodel` applies (it ignores the extra keys). */
482
+ export declare function fileMetamodelExtension(block: FileMetamodel): MetamodelExtension<string, string>;
483
+ //#endregion
419
484
  //#region src/serialization.d.ts
420
485
  export interface PistarElementJson {
421
486
  id: string;
@@ -494,12 +559,21 @@ export declare function inheritSourceLayout<M extends IstarModel<string, string>
494
559
  * `if (element.x && element.y)` silently drops them, which looks unintended.
495
560
  */
496
561
  export interface ParsePistarOptions<EK extends string = ElementKind, LK extends string = LinkKind> {
562
+ /**
563
+ * Read the file's own `"metamodel"` block (see `FileMetamodel`) and parse with `metamodel`
564
+ * (or iStar 2.0) extended by it. Default false: the block is kept as an unknown key and not
565
+ * applied, as before. A block whose kinds collide with the metamodel throws `MetamodelError`.
566
+ */
567
+ readonly fileMetamodel?: boolean;
497
568
  /**
498
569
  * The metamodel whose kinds the file may use. Default iStar 2.0: any other `type` throws,
499
570
  * as in the piStar tool. The parsed model remembers it (see `metamodelOf`).
500
571
  */
501
572
  readonly metamodel?: Metamodel<EK, LK>;
502
573
  }
574
+ export declare function parsePistar(input: string | PistarFile | Record<string, unknown>, options: ParsePistarOptions<string, string> & {
575
+ readonly fileMetamodel: true;
576
+ }): IstarModel<string, string>;
503
577
  export declare function parsePistar<EK extends string, LK extends string>(input: string | PistarFile | Record<string, unknown>, options: ParsePistarOptions<EK, LK> & {
504
578
  readonly metamodel: Metamodel<EK, LK>;
505
579
  }): IstarModel<EK, LK>;
@@ -519,6 +593,19 @@ export interface ToPistarOptions {
519
593
  export declare function toPistarObject<EK extends string, LK extends string>(input: IstarModel<EK, LK>, options?: ToPistarOptions): PistarFile;
520
594
  /** Serializes a model to piStar's JSON text (2-space indentation, no trailing newline). */
521
595
  export declare function toPistar<EK extends string, LK extends string>(model: IstarModel<EK, LK>, options?: ToPistarOptions): string;
596
+ /**
597
+ * The constructs the model's file declares in its `"metamodel"` block, when they were applied
598
+ * (read with `fileMetamodel: true`, or set with `withFileMetamodel`); `undefined` otherwise.
599
+ * Kinds the host supplied are never part of it.
600
+ */
601
+ export declare function fileMetamodelOf<EK extends string, LK extends string>(model: IstarModel<EK, LK>): FileMetamodel | undefined;
602
+ /**
603
+ * A copy of `model` whose file declares `block` (`null` removes the block): its metamodel is the
604
+ * host's extended by `block`, and `toPistar` writes the block. This is how a tool's "Add new"
605
+ * construct joins a model. Throws `MetamodelError` if the block is malformed, collides with the
606
+ * host's kinds, or leaves out a kind the model still uses.
607
+ */
608
+ export declare function withFileMetamodel<EK extends string, LK extends string>(model: IstarModel<EK, LK>, block: FileMetamodel | null): IstarModel<string, string>;
522
609
  declare namespace operations_d_exports {
523
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 };
524
611
  }
@@ -821,4 +908,137 @@ export declare function defineProperties<const S extends PropertyShape, const Ki
821
908
  }): PropertySchema<S, Kind>;
822
909
  export declare function validateModelProperties<EK extends string, LK extends string>(model: IstarModel<EK, LK>, schemas: readonly PropertySchema<PropertyShape, string>[]): ModelPropertyIssue[];
823
910
  //#endregion
911
+ //#region src/diagnostics.d.ts
912
+ /**
913
+ * The Goal Model Diagnostics Protocol: findings about a model's elements and links, published by
914
+ * any analyser (a language server, a validator, a simulation…) and anchored by element id rather
915
+ * than by text position. Data only: diagnostics are never part of the model and are never
916
+ * written to disk.
917
+ *
918
+ * See goal-controller issue #24 (option D). Producers publish per source; consumers see the
919
+ * union of every source, deduplicated by `(elementId, key, message)`.
920
+ */
921
+ export type DiagnosticSeverity = "error" | "warning" | "info" | "hint";
922
+ /** Most severe first. */
923
+ export declare const DIAGNOSTIC_SEVERITIES: readonly DiagnosticSeverity[];
924
+ /** A zero-based position in the producer's document (as in LSP). */
925
+ export interface DiagnosticPosition {
926
+ readonly line: number;
927
+ readonly character: number;
928
+ }
929
+ export interface DiagnosticRange {
930
+ readonly start: DiagnosticPosition;
931
+ readonly end: DiagnosticPosition;
932
+ }
933
+ export interface GoalDiagnostic {
934
+ /** Id of the element or link the diagnostic is about. */
935
+ readonly elementId: string;
936
+ /** The custom property it is about; absent for the element as a whole. */
937
+ readonly key?: string;
938
+ readonly severity: DiagnosticSeverity;
939
+ readonly message: string;
940
+ /** Who published it (e.g. `mutrose`, `goal-language`). */
941
+ readonly source?: string;
942
+ /** Where it was found in the producer's document, if it has one. */
943
+ readonly range?: DiagnosticRange;
944
+ readonly code?: string;
945
+ /** Producer data, passed through untouched. */
946
+ readonly data?: unknown;
947
+ }
948
+ /** Negative when `a` is more severe than `b`. */
949
+ export declare function compareSeverity(a: DiagnosticSeverity, b: DiagnosticSeverity): number;
950
+ /** The most severe severity in a list (what a badge shows), or `undefined` if it is empty. */
951
+ export declare function worstDiagnosticSeverity(diagnostics: readonly {
952
+ readonly severity: DiagnosticSeverity;
953
+ }[] | undefined): DiagnosticSeverity | undefined;
954
+ /**
955
+ * The union of several lists, in order, without duplicates: diagnostics with the same
956
+ * `(elementId, key, message)` count once, keeping the first one's position and the most severe
957
+ * severity among them.
958
+ */
959
+ export declare function mergeDiagnostics(lists: Iterable<readonly GoalDiagnostic[] | undefined>): GoalDiagnostic[];
960
+ /** Diagnostics by element (or link) id, each list in the input order. */
961
+ export declare function groupDiagnostics(diagnostics: readonly GoalDiagnostic[] | undefined): ReadonlyMap<string, readonly GoalDiagnostic[]>;
962
+ /**
963
+ * Holds the diagnostics of several sources. Each `publish` replaces that source's set, so a
964
+ * producer re-publishes everything it currently reports, as an LSP server does.
965
+ */
966
+ export interface DiagnosticsStore {
967
+ /**
968
+ * Replaces `source`'s diagnostics (an empty list clears them). Entries without a `source` get
969
+ * this one.
970
+ */
971
+ publish(source: string, diagnostics: readonly GoalDiagnostic[]): void;
972
+ /** Removes one source's diagnostics, or every source's. */
973
+ clear(source?: string): void;
974
+ /** Sources with diagnostics, in the order they first published. */
975
+ sources(): readonly string[];
976
+ /** One source's diagnostics. */
977
+ get(source: string): readonly GoalDiagnostic[];
978
+ /**
979
+ * Every source's diagnostics, merged (see `mergeDiagnostics`). The same array until the next
980
+ * change, so it can back `useSyncExternalStore`.
981
+ */
982
+ getAll(): readonly GoalDiagnostic[];
983
+ subscribe(listener: () => void): () => void;
984
+ }
985
+ export declare function createDiagnosticsStore(): DiagnosticsStore;
986
+ /**
987
+ * The parts of an LSP `Diagnostic` the adapter reads (structurally typed, so no LSP library is
988
+ * needed). The element is taken from `data.elementId`, or MutRoSe's `data.nodeId`; the property
989
+ * from `data.key`.
990
+ */
991
+ export interface LspDiagnosticLike {
992
+ readonly range?: DiagnosticRange;
993
+ /** LSP numbering: 1 error, 2 warning, 3 information, 4 hint. */
994
+ readonly severity?: number;
995
+ readonly message: string | {
996
+ readonly value: string;
997
+ };
998
+ readonly source?: string;
999
+ readonly code?: string | number | {
1000
+ readonly value: string | number;
1001
+ };
1002
+ readonly data?: unknown;
1003
+ }
1004
+ export interface FromLspOptions<D extends LspDiagnosticLike = LspDiagnosticLike> {
1005
+ /**
1006
+ * The element of a diagnostic whose `data` names none, e.g. by looking its range up in the
1007
+ * document. Return `undefined` to drop it.
1008
+ */
1009
+ readonly elementIdFor?: (diagnostic: D) => string | undefined;
1010
+ /**
1011
+ * `'vscode'` for `vscode.Diagnostic` objects, whose severity counts from 0 (error) to 3
1012
+ * (hint). Default `'lsp'`, the protocol's 1 to 4.
1013
+ */
1014
+ readonly severityNumbering?: "lsp" | "vscode";
1015
+ }
1016
+ /**
1017
+ * One LSP diagnostic anchored by `data.elementId` (or `data.nodeId`), or `undefined` when it
1018
+ * names no element. For range-anchored diagnostics use `fromLspDiagnostics` with `elementIdFor`.
1019
+ */
1020
+ export declare function fromLspDiagnostic(diagnostic: LspDiagnosticLike): GoalDiagnostic | undefined;
1021
+ /** LSP diagnostics as goal diagnostics; those that can't be anchored to an element are dropped. */
1022
+ export declare function fromLspDiagnostics<D extends LspDiagnosticLike>(diagnostics: readonly D[], options?: FromLspOptions<D>): GoalDiagnostic[];
1023
+ /**
1024
+ * The shape MutRoSe's VS Code extension posts to its webview: `{ nodeId, severity, message }`
1025
+ * (plus `range` and `source`). `nodeId` is missing when no node could be found.
1026
+ */
1027
+ export interface NodeIdDiagnostic {
1028
+ readonly nodeId?: string;
1029
+ readonly key?: string;
1030
+ readonly severity: DiagnosticSeverity | string;
1031
+ readonly message: string;
1032
+ readonly source?: string;
1033
+ readonly range?: DiagnosticRange;
1034
+ readonly code?: string;
1035
+ }
1036
+ /** One `{ nodeId, severity, message }` diagnostic, or `undefined` without a `nodeId`. */
1037
+ export declare function fromNodeIdDiagnostic(diagnostic: NodeIdDiagnostic): GoalDiagnostic | undefined;
1038
+ /**
1039
+ * `{ nodeId, severity, message }` diagnostics (MutRoSe) as goal diagnostics, dropping those
1040
+ * without a node: `store.publish('mutrose', fromNodeIdDiagnostics(message.diagnostics))`.
1041
+ */
1042
+ export declare function fromNodeIdDiagnostics(diagnostics: readonly NodeIdDiagnostic[]): GoalDiagnostic[];
1043
+ //#endregion
824
1044
  //# sourceMappingURL=index.d.cts.map
package/dist/index.d.ts CHANGED
@@ -128,6 +128,25 @@ export declare function validateModel(model: IstarModel): ModelIssue[];
128
128
  //#endregion
129
129
  //#region src/metamodels.d.ts
130
130
  export type ElementCategory = "actor" | "node";
131
+ /**
132
+ * Presentation hints a kind may carry, as data (core never draws). `@istar-ts/react` uses them as
133
+ * the defaults for the kind: a shape as SVG path data, the label's text box, a link's line.
134
+ */
135
+ export interface KindShape {
136
+ readonly path: string;
137
+ readonly viewBox?: string;
138
+ }
139
+ export interface KindTextBox {
140
+ readonly top: number;
141
+ readonly right: number;
142
+ readonly bottom: number;
143
+ readonly left: number;
144
+ }
145
+ export interface KindLine {
146
+ readonly dash?: string;
147
+ readonly marker?: string | false;
148
+ readonly markerFilled?: boolean;
149
+ }
131
150
  export type LinkCategory = "actor" | "node" | "dependency";
132
151
  /** A resolved element kind of a metamodel. */
133
152
  export interface ElementKindDefinition<K extends string = string> {
@@ -145,6 +164,9 @@ export interface ElementKindDefinition<K extends string = string> {
145
164
  readonly pistarType: string;
146
165
  /** Name of the extension that declared it; absent for iStar 2.0 kinds. */
147
166
  readonly extension?: string;
167
+ /** Presentation hints (drawn by `@istar-ts/react`). */
168
+ readonly shape?: KindShape;
169
+ readonly textBox?: KindTextBox;
148
170
  }
149
171
  /**
150
172
  * Declarative link rules, as piStar-ext's "Create a new Construct" dialog collects them:
@@ -184,6 +206,8 @@ export interface LinkKindDefinition<K extends string = string> {
184
206
  readonly check?: (context: LinkRuleContext) => LinkCheck;
185
207
  readonly pistarType: string;
186
208
  readonly extension?: string;
209
+ /** Presentation hint (drawn by `@istar-ts/react`). */
210
+ readonly line?: KindLine;
187
211
  }
188
212
  /** A metamodel: the element and link kinds a model may use, and their rules. */
189
213
  export interface Metamodel<EK extends string = ElementKind, LK extends string = LinkKind> {
@@ -222,6 +246,9 @@ export interface ElementKindDeclaration<K extends string = string> {
222
246
  * constructs as `istar.<Name>`, so `pistarType: 'istar.Planning'` reads its files.
223
247
  */
224
248
  readonly pistarType?: string;
249
+ /** Presentation hints, kept as data for renderers (`@istar-ts/react` draws them). */
250
+ readonly shape?: KindShape;
251
+ readonly textBox?: KindTextBox;
225
252
  }
226
253
  export interface LinkKindDeclaration<K extends string = string> {
227
254
  readonly kind: K;
@@ -237,6 +264,8 @@ export interface LinkKindDeclaration<K extends string = string> {
237
264
  /** Default: that of `behavesLike`, else none (no fixed label, no changeable value). */
238
265
  readonly info?: LinkKindInfo;
239
266
  readonly pistarType?: string;
267
+ /** Presentation hint, kept as data for renderers (`@istar-ts/react` draws it). */
268
+ readonly line?: KindLine;
240
269
  }
241
270
  /** A named set of new kinds, applied to a metamodel with `extendMetamodel`. */
242
271
  export interface MetamodelExtension<NEK extends string = string, NLK extends string = string> {
@@ -381,6 +410,10 @@ export type AnyIstarModel = IstarModel<string, string>;
381
410
  * the association.
382
411
  */
383
412
  export declare function withMetamodel<EK extends string, LK extends string>(model: IstarModel<string, string>, metamodel: Metamodel<EK, LK>): IstarModel<EK, LK>;
413
+ /** @internal Records the host part of a model's metamodel (used by serialization). */
414
+ export declare function setHostMetamodel(model: object, metamodel: AnyMetamodel | undefined): void;
415
+ /** @internal The host part of a model's metamodel, if the file declares the rest. */
416
+ export declare function hostMetamodelOf(model: object): AnyMetamodel | undefined;
384
417
  /** Gives `to` the metamodel of `from` (used for every model an operation derives). */
385
418
  export declare function inheritMetamodel<M extends IstarModel<string, string>>(from: IstarModel<string, string>, to: M): M;
386
419
  export declare function createEmptyModel<EK extends string, LK extends string>(diagram: Diagram | undefined, options: {
@@ -416,6 +449,38 @@ export declare function dependencyLinksOf<EK extends string, LK extends string>(
416
449
  outbound?: IstarLink<LK>;
417
450
  };
418
451
  //#endregion
452
+ //#region src/file-metamodel.d.ts
453
+ /** The top-level key of the block in piStar JSON. */
454
+ export declare const FILE_METAMODEL_KEY = "metamodel";
455
+ export interface FileElementKind extends Omit<ElementKindDeclaration<string>, "info"> {
456
+ readonly info?: {
457
+ readonly canBeInnerElement?: boolean;
458
+ readonly canBeDependum?: boolean;
459
+ readonly canBeOnPaper?: boolean;
460
+ };
461
+ readonly [key: string]: unknown;
462
+ }
463
+ export interface FileLinkKind extends Omit<LinkKindDeclaration<string>, "check"> {
464
+ readonly [key: string]: unknown;
465
+ }
466
+ /** The `"metamodel"` block of a model file. */
467
+ export interface FileMetamodel {
468
+ /** Identifies the constructs' dialect, e.g. `iStar4RationalAgents`. */
469
+ readonly name: string;
470
+ readonly elements?: readonly FileElementKind[];
471
+ readonly links?: readonly FileLinkKind[];
472
+ readonly [key: string]: unknown;
473
+ }
474
+ /**
475
+ * Checks that `value` is a well-formed `"metamodel"` block and returns it typed. Throws
476
+ * `MetamodelError` naming the offending path (`metamodel.elements[1].kind must be a string`).
477
+ * Whether its kinds fit a given metamodel (namespacing, collisions, `behavesLike` targets) is
478
+ * checked when it is applied, by `extendMetamodel`.
479
+ */
480
+ export declare function validateFileMetamodel(value: unknown, path?: string): FileMetamodel;
481
+ /** The block as an extension `extendMetamodel` applies (it ignores the extra keys). */
482
+ export declare function fileMetamodelExtension(block: FileMetamodel): MetamodelExtension<string, string>;
483
+ //#endregion
419
484
  //#region src/serialization.d.ts
420
485
  export interface PistarElementJson {
421
486
  id: string;
@@ -494,12 +559,21 @@ export declare function inheritSourceLayout<M extends IstarModel<string, string>
494
559
  * `if (element.x && element.y)` silently drops them, which looks unintended.
495
560
  */
496
561
  export interface ParsePistarOptions<EK extends string = ElementKind, LK extends string = LinkKind> {
562
+ /**
563
+ * Read the file's own `"metamodel"` block (see `FileMetamodel`) and parse with `metamodel`
564
+ * (or iStar 2.0) extended by it. Default false: the block is kept as an unknown key and not
565
+ * applied, as before. A block whose kinds collide with the metamodel throws `MetamodelError`.
566
+ */
567
+ readonly fileMetamodel?: boolean;
497
568
  /**
498
569
  * The metamodel whose kinds the file may use. Default iStar 2.0: any other `type` throws,
499
570
  * as in the piStar tool. The parsed model remembers it (see `metamodelOf`).
500
571
  */
501
572
  readonly metamodel?: Metamodel<EK, LK>;
502
573
  }
574
+ export declare function parsePistar(input: string | PistarFile | Record<string, unknown>, options: ParsePistarOptions<string, string> & {
575
+ readonly fileMetamodel: true;
576
+ }): IstarModel<string, string>;
503
577
  export declare function parsePistar<EK extends string, LK extends string>(input: string | PistarFile | Record<string, unknown>, options: ParsePistarOptions<EK, LK> & {
504
578
  readonly metamodel: Metamodel<EK, LK>;
505
579
  }): IstarModel<EK, LK>;
@@ -519,6 +593,19 @@ export interface ToPistarOptions {
519
593
  export declare function toPistarObject<EK extends string, LK extends string>(input: IstarModel<EK, LK>, options?: ToPistarOptions): PistarFile;
520
594
  /** Serializes a model to piStar's JSON text (2-space indentation, no trailing newline). */
521
595
  export declare function toPistar<EK extends string, LK extends string>(model: IstarModel<EK, LK>, options?: ToPistarOptions): string;
596
+ /**
597
+ * The constructs the model's file declares in its `"metamodel"` block, when they were applied
598
+ * (read with `fileMetamodel: true`, or set with `withFileMetamodel`); `undefined` otherwise.
599
+ * Kinds the host supplied are never part of it.
600
+ */
601
+ export declare function fileMetamodelOf<EK extends string, LK extends string>(model: IstarModel<EK, LK>): FileMetamodel | undefined;
602
+ /**
603
+ * A copy of `model` whose file declares `block` (`null` removes the block): its metamodel is the
604
+ * host's extended by `block`, and `toPistar` writes the block. This is how a tool's "Add new"
605
+ * construct joins a model. Throws `MetamodelError` if the block is malformed, collides with the
606
+ * host's kinds, or leaves out a kind the model still uses.
607
+ */
608
+ export declare function withFileMetamodel<EK extends string, LK extends string>(model: IstarModel<EK, LK>, block: FileMetamodel | null): IstarModel<string, string>;
522
609
  declare namespace operations_d_exports {
523
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 };
524
611
  }
@@ -821,4 +908,137 @@ export declare function defineProperties<const S extends PropertyShape, const Ki
821
908
  }): PropertySchema<S, Kind>;
822
909
  export declare function validateModelProperties<EK extends string, LK extends string>(model: IstarModel<EK, LK>, schemas: readonly PropertySchema<PropertyShape, string>[]): ModelPropertyIssue[];
823
910
  //#endregion
911
+ //#region src/diagnostics.d.ts
912
+ /**
913
+ * The Goal Model Diagnostics Protocol: findings about a model's elements and links, published by
914
+ * any analyser (a language server, a validator, a simulation…) and anchored by element id rather
915
+ * than by text position. Data only: diagnostics are never part of the model and are never
916
+ * written to disk.
917
+ *
918
+ * See goal-controller issue #24 (option D). Producers publish per source; consumers see the
919
+ * union of every source, deduplicated by `(elementId, key, message)`.
920
+ */
921
+ export type DiagnosticSeverity = "error" | "warning" | "info" | "hint";
922
+ /** Most severe first. */
923
+ export declare const DIAGNOSTIC_SEVERITIES: readonly DiagnosticSeverity[];
924
+ /** A zero-based position in the producer's document (as in LSP). */
925
+ export interface DiagnosticPosition {
926
+ readonly line: number;
927
+ readonly character: number;
928
+ }
929
+ export interface DiagnosticRange {
930
+ readonly start: DiagnosticPosition;
931
+ readonly end: DiagnosticPosition;
932
+ }
933
+ export interface GoalDiagnostic {
934
+ /** Id of the element or link the diagnostic is about. */
935
+ readonly elementId: string;
936
+ /** The custom property it is about; absent for the element as a whole. */
937
+ readonly key?: string;
938
+ readonly severity: DiagnosticSeverity;
939
+ readonly message: string;
940
+ /** Who published it (e.g. `mutrose`, `goal-language`). */
941
+ readonly source?: string;
942
+ /** Where it was found in the producer's document, if it has one. */
943
+ readonly range?: DiagnosticRange;
944
+ readonly code?: string;
945
+ /** Producer data, passed through untouched. */
946
+ readonly data?: unknown;
947
+ }
948
+ /** Negative when `a` is more severe than `b`. */
949
+ export declare function compareSeverity(a: DiagnosticSeverity, b: DiagnosticSeverity): number;
950
+ /** The most severe severity in a list (what a badge shows), or `undefined` if it is empty. */
951
+ export declare function worstDiagnosticSeverity(diagnostics: readonly {
952
+ readonly severity: DiagnosticSeverity;
953
+ }[] | undefined): DiagnosticSeverity | undefined;
954
+ /**
955
+ * The union of several lists, in order, without duplicates: diagnostics with the same
956
+ * `(elementId, key, message)` count once, keeping the first one's position and the most severe
957
+ * severity among them.
958
+ */
959
+ export declare function mergeDiagnostics(lists: Iterable<readonly GoalDiagnostic[] | undefined>): GoalDiagnostic[];
960
+ /** Diagnostics by element (or link) id, each list in the input order. */
961
+ export declare function groupDiagnostics(diagnostics: readonly GoalDiagnostic[] | undefined): ReadonlyMap<string, readonly GoalDiagnostic[]>;
962
+ /**
963
+ * Holds the diagnostics of several sources. Each `publish` replaces that source's set, so a
964
+ * producer re-publishes everything it currently reports, as an LSP server does.
965
+ */
966
+ export interface DiagnosticsStore {
967
+ /**
968
+ * Replaces `source`'s diagnostics (an empty list clears them). Entries without a `source` get
969
+ * this one.
970
+ */
971
+ publish(source: string, diagnostics: readonly GoalDiagnostic[]): void;
972
+ /** Removes one source's diagnostics, or every source's. */
973
+ clear(source?: string): void;
974
+ /** Sources with diagnostics, in the order they first published. */
975
+ sources(): readonly string[];
976
+ /** One source's diagnostics. */
977
+ get(source: string): readonly GoalDiagnostic[];
978
+ /**
979
+ * Every source's diagnostics, merged (see `mergeDiagnostics`). The same array until the next
980
+ * change, so it can back `useSyncExternalStore`.
981
+ */
982
+ getAll(): readonly GoalDiagnostic[];
983
+ subscribe(listener: () => void): () => void;
984
+ }
985
+ export declare function createDiagnosticsStore(): DiagnosticsStore;
986
+ /**
987
+ * The parts of an LSP `Diagnostic` the adapter reads (structurally typed, so no LSP library is
988
+ * needed). The element is taken from `data.elementId`, or MutRoSe's `data.nodeId`; the property
989
+ * from `data.key`.
990
+ */
991
+ export interface LspDiagnosticLike {
992
+ readonly range?: DiagnosticRange;
993
+ /** LSP numbering: 1 error, 2 warning, 3 information, 4 hint. */
994
+ readonly severity?: number;
995
+ readonly message: string | {
996
+ readonly value: string;
997
+ };
998
+ readonly source?: string;
999
+ readonly code?: string | number | {
1000
+ readonly value: string | number;
1001
+ };
1002
+ readonly data?: unknown;
1003
+ }
1004
+ export interface FromLspOptions<D extends LspDiagnosticLike = LspDiagnosticLike> {
1005
+ /**
1006
+ * The element of a diagnostic whose `data` names none, e.g. by looking its range up in the
1007
+ * document. Return `undefined` to drop it.
1008
+ */
1009
+ readonly elementIdFor?: (diagnostic: D) => string | undefined;
1010
+ /**
1011
+ * `'vscode'` for `vscode.Diagnostic` objects, whose severity counts from 0 (error) to 3
1012
+ * (hint). Default `'lsp'`, the protocol's 1 to 4.
1013
+ */
1014
+ readonly severityNumbering?: "lsp" | "vscode";
1015
+ }
1016
+ /**
1017
+ * One LSP diagnostic anchored by `data.elementId` (or `data.nodeId`), or `undefined` when it
1018
+ * names no element. For range-anchored diagnostics use `fromLspDiagnostics` with `elementIdFor`.
1019
+ */
1020
+ export declare function fromLspDiagnostic(diagnostic: LspDiagnosticLike): GoalDiagnostic | undefined;
1021
+ /** LSP diagnostics as goal diagnostics; those that can't be anchored to an element are dropped. */
1022
+ export declare function fromLspDiagnostics<D extends LspDiagnosticLike>(diagnostics: readonly D[], options?: FromLspOptions<D>): GoalDiagnostic[];
1023
+ /**
1024
+ * The shape MutRoSe's VS Code extension posts to its webview: `{ nodeId, severity, message }`
1025
+ * (plus `range` and `source`). `nodeId` is missing when no node could be found.
1026
+ */
1027
+ export interface NodeIdDiagnostic {
1028
+ readonly nodeId?: string;
1029
+ readonly key?: string;
1030
+ readonly severity: DiagnosticSeverity | string;
1031
+ readonly message: string;
1032
+ readonly source?: string;
1033
+ readonly range?: DiagnosticRange;
1034
+ readonly code?: string;
1035
+ }
1036
+ /** One `{ nodeId, severity, message }` diagnostic, or `undefined` without a `nodeId`. */
1037
+ export declare function fromNodeIdDiagnostic(diagnostic: NodeIdDiagnostic): GoalDiagnostic | undefined;
1038
+ /**
1039
+ * `{ nodeId, severity, message }` diagnostics (MutRoSe) as goal diagnostics, dropping those
1040
+ * without a node: `store.publish('mutrose', fromNodeIdDiagnostics(message.diagnostics))`.
1041
+ */
1042
+ export declare function fromNodeIdDiagnostics(diagnostics: readonly NodeIdDiagnostic[]): GoalDiagnostic[];
1043
+ //#endregion
824
1044
  //# sourceMappingURL=index.d.ts.map