@openmbee/opensysml 0.9.2 → 0.10.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 +355 -33
- package/dist/browser/index.d.ts +9 -0
- package/dist/browser/index.js +16 -0
- package/dist/browser/wasm-worker.d.ts +1 -0
- package/dist/browser/wasm-worker.js +2 -0
- package/dist/browser/wasm.d.ts +17 -0
- package/dist/browser/wasm.js +94 -0
- package/dist/core/arguments.d.ts +4 -0
- package/dist/core/arguments.js +19 -0
- package/dist/core/capabilities.d.ts +90 -9
- package/dist/core/capabilities.js +111 -10
- package/dist/core/connection.d.ts +203 -2
- package/dist/core/connection.js +810 -17
- package/dist/core/conversion.d.ts +153 -0
- package/dist/core/conversion.js +191 -0
- package/dist/core/document.d.ts +188 -0
- package/dist/core/document.js +457 -0
- package/dist/core/edit.d.ts +446 -0
- package/dist/core/edit.js +1994 -0
- package/dist/core/engines.d.ts +64 -0
- package/dist/core/engines.js +74 -0
- package/dist/core/errors.d.ts +164 -2
- package/dist/core/errors.js +209 -3
- package/dist/core/exploration.d.ts +71 -0
- package/dist/core/exploration.js +116 -0
- package/dist/core/graphs.d.ts +15 -0
- package/dist/core/graphs.js +3 -0
- package/dist/core/index.d.ts +30 -9
- package/dist/core/index.js +14 -5
- package/dist/core/model.d.ts +168 -8
- package/dist/core/model.js +258 -31
- package/dist/core/package.d.ts +2 -0
- package/dist/core/package.js +2 -0
- package/dist/core/query.d.ts +50 -0
- package/dist/core/query.js +197 -0
- package/dist/core/render-view.d.ts +97 -0
- package/dist/core/render-view.js +120 -0
- package/dist/core/sources.d.ts +34 -0
- package/dist/core/sources.js +134 -0
- package/dist/core/status.d.ts +9 -2
- package/dist/core/status.js +24 -8
- package/dist/core/typed.d.ts +71 -0
- package/dist/core/typed.js +245 -0
- package/dist/core/values.d.ts +127 -8
- package/dist/core/values.js +536 -30
- package/dist/core/verdict.d.ts +271 -0
- package/dist/core/verdict.js +567 -0
- package/dist/core/wasm.d.ts +114 -0
- package/dist/core/wasm.js +514 -0
- package/dist/generated/sysml_pb.d.ts +1062 -15
- package/dist/generated/sysml_pb.js +200 -100
- package/dist/node/generate-cli.d.ts +2 -0
- package/dist/node/generate-cli.js +10 -0
- package/dist/node/generate.d.ts +99 -0
- package/dist/node/generate.js +757 -0
- package/dist/node/index.d.ts +29 -2
- package/dist/node/index.js +211 -10
- package/dist/node/service.d.ts +5 -3
- package/dist/node/service.js +32 -26
- package/dist/node/wasm-source.d.ts +18 -0
- package/dist/node/wasm-source.js +103 -0
- package/dist/node/wasm-worker.d.ts +1 -0
- package/dist/node/wasm-worker.js +10 -0
- package/dist/node/wasm.d.ts +17 -0
- package/dist/node/wasm.js +63 -0
- package/package.json +19 -7
- package/release-digests.json +105 -0
package/dist/core/model.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
// The ergonomic surface: a loaded model, its symbols, and the objects it
|
|
2
2
|
// instantiates. Everything here is built on Connection.rpc.
|
|
3
3
|
import { CAPABILITY_EVALUATE_SUBJECT, CAPABILITY_INLINE_LANGUAGE, CAPABILITY_STRICT_CONFORMANCE, requireCapability, upgradeRemedy, } from "./capabilities.js";
|
|
4
|
+
import { requireString, requireSourceText } from "./arguments.js";
|
|
4
5
|
import { EvaluationError, OpenSysMLError, ParseError, SymbolNotFoundError } from "./errors.js";
|
|
6
|
+
import { requireLanguage } from "./sources.js";
|
|
5
7
|
import { callRpc } from "./status.js";
|
|
6
8
|
import { decodeValue } from "./values.js";
|
|
7
9
|
/** How alike two names must be for one to be suggested for the other. */
|
|
@@ -31,6 +33,54 @@ function editDistance(left, right) {
|
|
|
31
33
|
}
|
|
32
34
|
return previous[right.length] ?? 0;
|
|
33
35
|
}
|
|
36
|
+
/** Resolves `strictConformance` and its `strict` alias; differing values refuse. */
|
|
37
|
+
export function strictConformanceOf(options) {
|
|
38
|
+
if (options.strict !== undefined &&
|
|
39
|
+
options.strictConformance !== undefined &&
|
|
40
|
+
options.strict !== options.strictConformance) {
|
|
41
|
+
throw new RangeError(`strict (${options.strict}) and strictConformance (${options.strictConformance}) disagree; ` +
|
|
42
|
+
"pass only strictConformance");
|
|
43
|
+
}
|
|
44
|
+
return options.strictConformance ?? options.strict;
|
|
45
|
+
}
|
|
46
|
+
/** The integer one bound spells, or undefined when it spells none. */
|
|
47
|
+
function multiplicityBound(bound) {
|
|
48
|
+
const trimmed = bound.trim();
|
|
49
|
+
if (!/^[+-]?\d+$/.test(trimmed)) {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
return Number.parseInt(trimmed, 10);
|
|
53
|
+
}
|
|
54
|
+
/** Builds a Multiplicity whose predicates mirror Python's. */
|
|
55
|
+
function multiplicityOf(lower, upper) {
|
|
56
|
+
const lowerBound = lower === "" ? undefined : multiplicityBound(lower);
|
|
57
|
+
return {
|
|
58
|
+
lower,
|
|
59
|
+
upper,
|
|
60
|
+
isOptional: lowerBound === undefined ? undefined : lowerBound === 0,
|
|
61
|
+
isCollection: isCollectionUpper(upper),
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
/** Whether an upper bound admits more than one: unknown for none, or one that is not a number. */
|
|
65
|
+
function isCollectionUpper(upper) {
|
|
66
|
+
if (upper === "") {
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
if (upper === "*") {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
const bound = multiplicityBound(upper);
|
|
73
|
+
return bound === undefined ? undefined : bound > 1;
|
|
74
|
+
}
|
|
75
|
+
/** The symbols of one level of a model, then those of the levels below it. */
|
|
76
|
+
async function* walkLevels(level) {
|
|
77
|
+
if (level.length === 0) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
yield* level;
|
|
81
|
+
const children = await Promise.all(level.map((symbol) => symbol.children()));
|
|
82
|
+
yield* walkLevels(children.flat());
|
|
83
|
+
}
|
|
34
84
|
/** A model the service has parsed and holds under its hash. */
|
|
35
85
|
export class Model {
|
|
36
86
|
connection;
|
|
@@ -38,43 +88,87 @@ export class Model {
|
|
|
38
88
|
hash;
|
|
39
89
|
/** Diagnostics the parse reported, in the order the service reported them. */
|
|
40
90
|
diagnostics;
|
|
41
|
-
|
|
91
|
+
/** The name of each document this model was parsed from, empty for an adopted model. */
|
|
92
|
+
documents;
|
|
93
|
+
rootSymbols;
|
|
42
94
|
ownsConnection;
|
|
43
95
|
constructor(init) {
|
|
44
96
|
this.connection = init.connection;
|
|
45
97
|
this.hash = init.hash;
|
|
46
|
-
this.
|
|
98
|
+
this.rootSymbols = init.roots ?? [];
|
|
47
99
|
this.diagnostics = init.diagnostics;
|
|
48
100
|
this.ownsConnection = init.ownsConnection;
|
|
101
|
+
this.documents = init.documents ?? [];
|
|
102
|
+
this.sourcePath = init.sourcePath;
|
|
49
103
|
}
|
|
50
104
|
/** Adopts a model the service already holds, by the hash it holds it under. */
|
|
51
105
|
static adopt(connection, hash) {
|
|
52
106
|
return new Model({ connection, hash, diagnostics: [], ownsConnection: false });
|
|
53
107
|
}
|
|
108
|
+
/** Builds a model of several roots, from a ParseSources response. */
|
|
109
|
+
static fromRoots(connection, hash, roots, diagnostics, options = {}) {
|
|
110
|
+
return new Model({
|
|
111
|
+
connection,
|
|
112
|
+
hash,
|
|
113
|
+
roots: roots.map((info) => new ModelSymbol(connection, hash, info)),
|
|
114
|
+
diagnostics,
|
|
115
|
+
ownsConnection: options.ownsConnection ?? false,
|
|
116
|
+
...(options.documents === undefined ? {} : { documents: options.documents }),
|
|
117
|
+
});
|
|
118
|
+
}
|
|
54
119
|
/** Whether this model was parsed here, and so knows its root symbol. */
|
|
55
120
|
get parsed() {
|
|
56
|
-
return this.
|
|
121
|
+
return this.rootSymbols.length > 0;
|
|
57
122
|
}
|
|
58
123
|
/** The model's root namespace. An adopted model has none: look symbols up by id. */
|
|
59
124
|
get root() {
|
|
60
|
-
if (this.
|
|
125
|
+
if (this.rootSymbols.length === 0) {
|
|
61
126
|
throw new OpenSysMLError(`model ${this.hash} was adopted by hash, not parsed here, so its root is unknown; ` +
|
|
62
127
|
"look a symbol up by its qualified name with symbolById()");
|
|
63
128
|
}
|
|
64
|
-
return this.
|
|
129
|
+
return this.rootSymbols[0];
|
|
130
|
+
}
|
|
131
|
+
/** One root per document parsed; the one symbol {@link root} names is the first. */
|
|
132
|
+
get roots() {
|
|
133
|
+
return this.rootSymbols;
|
|
134
|
+
}
|
|
135
|
+
/** The path this model was loaded from, when it was parsed from a file;
|
|
136
|
+
* inline content and parseSources models have none, whatever they are named. */
|
|
137
|
+
sourcePath;
|
|
138
|
+
/** The error-severity diagnostics the parse reported. */
|
|
139
|
+
get errors() {
|
|
140
|
+
return this.diagnostics.filter((diagnostic) => diagnostic.severity === "error");
|
|
141
|
+
}
|
|
142
|
+
/** Whether the parse reported no error-severity diagnostic. */
|
|
143
|
+
get ok() {
|
|
144
|
+
return this.errors.length === 0;
|
|
145
|
+
}
|
|
146
|
+
/** Raises a {@link ParseError} carrying this model when its parse reported errors. */
|
|
147
|
+
raiseForErrors() {
|
|
148
|
+
if (this.hasErrors) {
|
|
149
|
+
throw new ParseError(this.errors.map((diagnostic) => diagnostic.message).join("\n"), this.errors, {
|
|
150
|
+
model: this,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
return this;
|
|
65
154
|
}
|
|
66
155
|
/** Parses a source over `connection`. Used by Connection.load / Connection.loads. */
|
|
67
156
|
static async parse(connection, source, options = {}, ownsConnection = false) {
|
|
157
|
+
if (source.source.case === "content") {
|
|
158
|
+
requireSourceText("source", source.source.value);
|
|
159
|
+
}
|
|
68
160
|
if (options.language !== undefined) {
|
|
161
|
+
requireLanguage(options.language);
|
|
69
162
|
requireCapability(connection.info, CAPABILITY_INLINE_LANGUAGE, upgradeRemedy(CAPABILITY_INLINE_LANGUAGE));
|
|
70
163
|
}
|
|
71
|
-
|
|
164
|
+
const strictConformance = strictConformanceOf(options);
|
|
165
|
+
if (strictConformance === true) {
|
|
72
166
|
requireCapability(connection.info, CAPABILITY_STRICT_CONFORMANCE, upgradeRemedy(CAPABILITY_STRICT_CONFORMANCE));
|
|
73
167
|
}
|
|
74
168
|
const response = await callRpc(connection.rpc.parseFile({
|
|
75
169
|
source: source.source,
|
|
76
170
|
...(options.language === undefined ? {} : { language: options.language }),
|
|
77
|
-
...(
|
|
171
|
+
...(strictConformance === undefined ? {} : { strictConformance }),
|
|
78
172
|
}, connection.callOptions()), source.source.case === "filePath" ? "file" : "model");
|
|
79
173
|
const diagnostics = response.diagnostics.map(decodeDiagnostic);
|
|
80
174
|
if (response.error !== "") {
|
|
@@ -86,9 +180,12 @@ export class Model {
|
|
|
86
180
|
return new Model({
|
|
87
181
|
connection,
|
|
88
182
|
hash: response.modelHash,
|
|
89
|
-
|
|
183
|
+
roots: [new ModelSymbol(connection, response.modelHash, response.root)],
|
|
90
184
|
diagnostics,
|
|
91
185
|
ownsConnection,
|
|
186
|
+
...(source.source.case === "filePath"
|
|
187
|
+
? { documents: [source.source.value], sourcePath: source.source.value }
|
|
188
|
+
: {}),
|
|
92
189
|
});
|
|
93
190
|
}
|
|
94
191
|
/** Whether the parse reported an error-severity diagnostic. */
|
|
@@ -97,6 +194,7 @@ export class Model {
|
|
|
97
194
|
}
|
|
98
195
|
/** Evaluates a SysML expression against this model. */
|
|
99
196
|
async eval(expression, options = {}) {
|
|
197
|
+
requireString("expression", expression);
|
|
100
198
|
if (options.subject !== undefined) {
|
|
101
199
|
requireCapability(this.connection.info, CAPABILITY_EVALUATE_SUBJECT, upgradeRemedy(CAPABILITY_EVALUATE_SUBJECT));
|
|
102
200
|
}
|
|
@@ -113,30 +211,158 @@ export class Model {
|
|
|
113
211
|
}
|
|
114
212
|
/** Looks a symbol up by short name, FQN or id; throws when the model declares none. */
|
|
115
213
|
async symbol(name) {
|
|
116
|
-
|
|
117
|
-
|
|
214
|
+
requireString("name", name);
|
|
215
|
+
// The empty name names the model itself, as Python's model.get("") does.
|
|
216
|
+
if (name === "") {
|
|
217
|
+
return this.parsed ? this.root : this.symbolById(name);
|
|
118
218
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
219
|
+
if (this.looksQualified(name) || !this.parsed) {
|
|
220
|
+
// A qualified name or a name on an adopted model is resolved by the
|
|
221
|
+
// service; one it cannot resolve is searched for, as Python's find does.
|
|
222
|
+
try {
|
|
223
|
+
return await this.symbolById(name);
|
|
224
|
+
}
|
|
225
|
+
catch (error) {
|
|
226
|
+
if (!(error instanceof SymbolNotFoundError)) {
|
|
227
|
+
throw error;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
const qualified = await this.find(name);
|
|
231
|
+
if (qualified !== undefined) {
|
|
232
|
+
return qualified;
|
|
233
|
+
}
|
|
234
|
+
throw new SymbolNotFoundError(name, await this.nearNames(name));
|
|
123
235
|
}
|
|
124
236
|
const found = await this.find(name);
|
|
125
237
|
if (found === undefined) {
|
|
238
|
+
// A short name may still be one the service resolves directly, as an id.
|
|
239
|
+
try {
|
|
240
|
+
return await this.symbolById(name);
|
|
241
|
+
}
|
|
242
|
+
catch (error) {
|
|
243
|
+
if (!(error instanceof SymbolNotFoundError)) {
|
|
244
|
+
throw error;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
126
247
|
throw new SymbolNotFoundError(name, await this.nearNames(name));
|
|
127
248
|
}
|
|
128
249
|
return found;
|
|
129
250
|
}
|
|
251
|
+
/** Writes this model out in `toFormat`. */
|
|
252
|
+
convert(toFormat, options = {}) {
|
|
253
|
+
return this.connection.convert(toFormat, { modelHash: this.hash }, options);
|
|
254
|
+
}
|
|
255
|
+
/** This model written in SysML notation. */
|
|
256
|
+
toSysml() {
|
|
257
|
+
return this.convert("sysml");
|
|
258
|
+
}
|
|
259
|
+
/** This model written as RDF Turtle. */
|
|
260
|
+
toTurtle() {
|
|
261
|
+
return this.convert("ttl");
|
|
262
|
+
}
|
|
263
|
+
/** This model written as API JSON. */
|
|
264
|
+
toApiJson() {
|
|
265
|
+
return this.convert("api-json");
|
|
266
|
+
}
|
|
267
|
+
/** Runs a SysML v2 API & Services Query over this model. */
|
|
268
|
+
query(options = {}) {
|
|
269
|
+
return this.connection.query(this.hash, options);
|
|
270
|
+
}
|
|
271
|
+
/** Runs a named document query against this model. */
|
|
272
|
+
runDocumentQuery(queryId, bindings) {
|
|
273
|
+
return this.connection.runDocumentQuery(this.hash, queryId, bindings);
|
|
274
|
+
}
|
|
275
|
+
/** Renders a named document of this model to Markdown or HTML. */
|
|
276
|
+
renderDocument(documentId, options = {}) {
|
|
277
|
+
return this.connection.renderDocument(this.hash, documentId, options);
|
|
278
|
+
}
|
|
279
|
+
/** Renders a named view or targeted pseudo-view as diagram data. */
|
|
280
|
+
renderView(viewName, options = {}) {
|
|
281
|
+
return this.connection.renderView(this.hash, viewName, options);
|
|
282
|
+
}
|
|
283
|
+
/** Exports the lowered graph of an action or state machine of this model as `graphs:1` JSON. */
|
|
284
|
+
exportGraphs(subject) {
|
|
285
|
+
return this.connection.exportGraphs(this.hash, subject);
|
|
286
|
+
}
|
|
287
|
+
/** Starts an edit of this model, to be applied in one call. */
|
|
288
|
+
edit() {
|
|
289
|
+
return this.connection.edit(this.hash);
|
|
290
|
+
}
|
|
291
|
+
/** Executes an action definition of this model. */
|
|
292
|
+
executeAction(actionSymbolId, options = {}) {
|
|
293
|
+
return this.connection.executeAction(this.hash, actionSymbolId, options);
|
|
294
|
+
}
|
|
295
|
+
/** Runs an action once per valid order of its choice points. */
|
|
296
|
+
exploreAction(actionSymbolId, options = {}) {
|
|
297
|
+
return this.connection.exploreAction(this.hash, actionSymbolId, options);
|
|
298
|
+
}
|
|
299
|
+
/** Executes a state machine of this model. */
|
|
300
|
+
executeState(stateMachineSymbolId, options = {}) {
|
|
301
|
+
return this.connection.executeState(this.hash, stateMachineSymbolId, options);
|
|
302
|
+
}
|
|
303
|
+
/** Runs a state machine once per valid order of its choice points. */
|
|
304
|
+
exploreState(stateMachineSymbolId, options = {}) {
|
|
305
|
+
return this.connection.exploreState(this.hash, stateMachineSymbolId, options);
|
|
306
|
+
}
|
|
307
|
+
/** Asks whether a constraint of this model holds. */
|
|
308
|
+
verifyConstraint(symbolId, options = {}) {
|
|
309
|
+
return this.connection.verifyConstraint(this.hash, symbolId, options);
|
|
310
|
+
}
|
|
311
|
+
/** Asks whether a requirement of this model is satisfied. */
|
|
312
|
+
verifyRequirement(symbolId, options = {}) {
|
|
313
|
+
return this.connection.verifyRequirement(this.hash, symbolId, options);
|
|
314
|
+
}
|
|
315
|
+
/** Asks whether this model's satisfaction assertions hold. */
|
|
316
|
+
verifySatisfaction(options = {}) {
|
|
317
|
+
return this.connection.verifySatisfaction(this.hash, options);
|
|
318
|
+
}
|
|
319
|
+
/** Whether every verdict {@link verifySatisfaction} returns holds. */
|
|
320
|
+
async satisfied(options = {}) {
|
|
321
|
+
const verdicts = await this.verifySatisfaction(options);
|
|
322
|
+
return verdicts.every((verdict) => verdict.verdict.kind === "holds");
|
|
323
|
+
}
|
|
324
|
+
/** Checks every assertion about an object of this model's parts. */
|
|
325
|
+
validateInstance(symbolId, options = {}) {
|
|
326
|
+
return this.connection.validateInstance(this.hash, symbolId, options);
|
|
327
|
+
}
|
|
328
|
+
/** Invokes a calculation of this model. */
|
|
329
|
+
calc(symbolId, options = {}) {
|
|
330
|
+
return this.connection.calc(this.hash, symbolId, options);
|
|
331
|
+
}
|
|
332
|
+
/** Runs an analysis case of this model. */
|
|
333
|
+
runAnalysis(symbolId, options = {}) {
|
|
334
|
+
return this.connection.runAnalysis(this.hash, symbolId, options);
|
|
335
|
+
}
|
|
336
|
+
/** Runs an analysis case once per valid order of its choice points. */
|
|
337
|
+
exploreAnalysis(symbolId, options = {}) {
|
|
338
|
+
return this.connection.exploreAnalysis(this.hash, symbolId, options);
|
|
339
|
+
}
|
|
340
|
+
/** Runs an analysis case or calc of this model once per row of a sweep. */
|
|
341
|
+
runSweep(symbolId, ranges, options = {}) {
|
|
342
|
+
return this.connection.runSweep(this.hash, symbolId, ranges, options);
|
|
343
|
+
}
|
|
344
|
+
/** The diagnostics the service reports for this model now — for a model of
|
|
345
|
+
* several documents, or one parsed before later edits changed it. */
|
|
346
|
+
async refreshDiagnostics() {
|
|
347
|
+
const response = await callRpc(this.connection.rpc.getDiagnostics({ modelHash: this.hash }, this.connection.callOptions()));
|
|
348
|
+
return response.diagnostics.map(decodeDiagnostic);
|
|
349
|
+
}
|
|
130
350
|
/** Looks a symbol up by its qualified name, in one call. */
|
|
131
351
|
async symbolById(id) {
|
|
352
|
+
requireString("id", id);
|
|
132
353
|
const response = await callRpc(this.connection.rpc.getSymbol({ modelHash: this.hash, symbolId: id }, this.connection.callOptions()));
|
|
133
354
|
if (response.symbol === undefined) {
|
|
355
|
+
// A single call: near names are symbol()'s to compute.
|
|
134
356
|
throw new SymbolNotFoundError(id);
|
|
135
357
|
}
|
|
136
358
|
return new ModelSymbol(this.connection, this.hash, response.symbol);
|
|
137
359
|
}
|
|
138
360
|
/** Looks a symbol up by short name, FQN or id, breadth-first from the root. */
|
|
139
361
|
async find(name) {
|
|
362
|
+
requireString("name", name);
|
|
363
|
+
if (name === "") {
|
|
364
|
+
return this.parsed ? this.root : undefined;
|
|
365
|
+
}
|
|
140
366
|
for await (const symbol of this.walk()) {
|
|
141
367
|
if (symbol.name === name || symbol.id === name) {
|
|
142
368
|
return symbol;
|
|
@@ -146,18 +372,11 @@ export class Model {
|
|
|
146
372
|
}
|
|
147
373
|
/** Every symbol of the model, breadth-first from the root. */
|
|
148
374
|
async *walk() {
|
|
149
|
-
|
|
150
|
-
while (queue.length > 0) {
|
|
151
|
-
const current = queue.shift();
|
|
152
|
-
if (current === undefined) {
|
|
153
|
-
break;
|
|
154
|
-
}
|
|
155
|
-
yield current;
|
|
156
|
-
queue.push(...(await current.children()));
|
|
157
|
-
}
|
|
375
|
+
yield* walkLevels([...this.rootSymbols]);
|
|
158
376
|
}
|
|
159
377
|
/** Instantiates a part or usage, by short name, FQN or id. */
|
|
160
378
|
async instantiate(name) {
|
|
379
|
+
requireString("name", name);
|
|
161
380
|
const id = this.looksQualified(name) ? name : (await this.symbol(name)).id;
|
|
162
381
|
const response = await callRpc(this.connection.rpc.instantiate({ modelHash: this.hash, symbolId: id }, this.connection.callOptions()));
|
|
163
382
|
if (response.error !== "") {
|
|
@@ -179,7 +398,7 @@ export class Model {
|
|
|
179
398
|
}
|
|
180
399
|
/** Whether a name is one the service can resolve directly, without a search. */
|
|
181
400
|
looksQualified(name) {
|
|
182
|
-
return name.includes("::") || name === this.
|
|
401
|
+
return name.includes("::") || name === this.rootSymbols[0]?.id;
|
|
183
402
|
}
|
|
184
403
|
/** The names of the model closest to one it has not got, best first. */
|
|
185
404
|
async nearNames(name) {
|
|
@@ -190,9 +409,16 @@ export class Model {
|
|
|
190
409
|
if (symbol.name === "") {
|
|
191
410
|
continue;
|
|
192
411
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
412
|
+
// A short name and a qualified one are both candidates, either being
|
|
413
|
+
// what a mistyped lookup may have meant.
|
|
414
|
+
for (const candidate of [symbol.name, symbol.id]) {
|
|
415
|
+
if (candidate === "") {
|
|
416
|
+
continue;
|
|
417
|
+
}
|
|
418
|
+
const score = similarity(name.toLowerCase(), candidate.toLowerCase());
|
|
419
|
+
if (score >= NEAR_ENOUGH) {
|
|
420
|
+
scored.push({ id: candidate, score });
|
|
421
|
+
}
|
|
196
422
|
}
|
|
197
423
|
seen += 1;
|
|
198
424
|
if (seen === NEAR_SEARCH_LIMIT) {
|
|
@@ -247,7 +473,7 @@ export class ModelSymbol {
|
|
|
247
473
|
this.multiplicity =
|
|
248
474
|
info.multiplicity === undefined
|
|
249
475
|
? undefined
|
|
250
|
-
:
|
|
476
|
+
: multiplicityOf(info.multiplicity.lower, info.multiplicity.upper);
|
|
251
477
|
this.specializations = info.specializations.map((specialization) => ({
|
|
252
478
|
kind: specialization.kind,
|
|
253
479
|
declared: specialization.declared,
|
|
@@ -258,9 +484,9 @@ export class ModelSymbol {
|
|
|
258
484
|
}
|
|
259
485
|
/** The symbols this one owns, fetched one call each. */
|
|
260
486
|
async children() {
|
|
487
|
+
const responses = await Promise.all(this.childIds.map((id) => callRpc(this.connection.rpc.getSymbol({ modelHash: this.modelHash, symbolId: id }, this.connection.callOptions()))));
|
|
261
488
|
const children = [];
|
|
262
|
-
for (const
|
|
263
|
-
const response = await callRpc(this.connection.rpc.getSymbol({ modelHash: this.modelHash, symbolId: id }, this.connection.callOptions()));
|
|
489
|
+
for (const response of responses) {
|
|
264
490
|
if (response.symbol !== undefined) {
|
|
265
491
|
children.push(new ModelSymbol(this.connection, this.modelHash, response.symbol));
|
|
266
492
|
}
|
|
@@ -320,7 +546,8 @@ function decodeFeatureValue(value) {
|
|
|
320
546
|
}
|
|
321
547
|
return { kind: "single", value: decodeValue(value.value), materialized: value.materialized };
|
|
322
548
|
}
|
|
323
|
-
|
|
549
|
+
/** Reads a wire `Diagnostic` into this client's own {@link ModelDiagnostic}. */
|
|
550
|
+
export function decodeDiagnostic(diagnostic) {
|
|
324
551
|
const span = diagnostic.span;
|
|
325
552
|
return {
|
|
326
553
|
severity: diagnostic.severity,
|
package/dist/core/package.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
/** The npm name this client is published under; package.json's "name" must match it. */
|
|
2
2
|
export declare const PACKAGE_NAME = "@openmbee/opensysml";
|
|
3
|
+
/** The optional npm package that carries the combined WebAssembly module. */
|
|
4
|
+
export declare const WASM_PACKAGE = "@openmbee/opensysml-wasm";
|
|
3
5
|
/** Prefix of the per-platform packages that carry sysml-grpc: `${prefix}<os>-<cpu>`. */
|
|
4
6
|
export declare const PLATFORM_PACKAGE_PREFIX = "@openmbee/opensysml-sysml-grpc-";
|
package/dist/core/package.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
/** The npm name this client is published under; package.json's "name" must match it. */
|
|
2
2
|
export const PACKAGE_NAME = "@openmbee/opensysml";
|
|
3
|
+
/** The optional npm package that carries the combined WebAssembly module. */
|
|
4
|
+
export const WASM_PACKAGE = `${PACKAGE_NAME}-wasm`;
|
|
3
5
|
/** Prefix of the per-platform packages that carry sysml-grpc: `${prefix}<os>-<cpu>`. */
|
|
4
6
|
export const PLATFORM_PACKAGE_PREFIX = `${PACKAGE_NAME}-sysml-grpc-`;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { Query, QueryResponse } from "../generated/sysml_pb.js";
|
|
2
|
+
/** `@type` of the standard's query resource. */
|
|
3
|
+
export declare const TYPE_QUERY = "Query";
|
|
4
|
+
/** `@type` of a single-property constraint. */
|
|
5
|
+
export declare const TYPE_PRIMITIVE_CONSTRAINT = "PrimitiveConstraint";
|
|
6
|
+
/** `@type` of a constraint over nested constraints. */
|
|
7
|
+
export declare const TYPE_COMPOSITE_CONSTRAINT = "CompositeConstraint";
|
|
8
|
+
/** An element a query selected. */
|
|
9
|
+
export declare class QueryElement {
|
|
10
|
+
/** Qualified name of the element, which is what a scope names it by. */
|
|
11
|
+
readonly id: string;
|
|
12
|
+
/** The element's metamodel type, e.g. `PartUsage`. */
|
|
13
|
+
readonly type: string;
|
|
14
|
+
/** The selected properties it has; one it does not have is absent. */
|
|
15
|
+
readonly properties: Readonly<Record<string, string>>;
|
|
16
|
+
constructor(init: {
|
|
17
|
+
id: string;
|
|
18
|
+
type: string;
|
|
19
|
+
properties: Record<string, string>;
|
|
20
|
+
});
|
|
21
|
+
/** Value of a selected property, or `fallback` if the element has none. */
|
|
22
|
+
get(propertyName: string, fallback?: string): string | undefined;
|
|
23
|
+
/** The element as the standard's JSON names it: `@id`, `@type`, properties. */
|
|
24
|
+
asDict(): Record<string, string>;
|
|
25
|
+
toString(): string;
|
|
26
|
+
}
|
|
27
|
+
/** A scope entry: an element's qualified name or an `@id` reference. */
|
|
28
|
+
export type ScopeEntry = string | {
|
|
29
|
+
"@id": string;
|
|
30
|
+
};
|
|
31
|
+
/** A constraint, as the standard's JSON writes it. */
|
|
32
|
+
export type ConstraintPayload = Record<string, unknown>;
|
|
33
|
+
/** The standard's `Query` object, as JSON. */
|
|
34
|
+
export type QueryPayload = Record<string, unknown>;
|
|
35
|
+
/** Keyword form of a query, exclusive with `payload`. */
|
|
36
|
+
export interface QueryForm {
|
|
37
|
+
scope?: readonly ScopeEntry[];
|
|
38
|
+
select?: readonly string[];
|
|
39
|
+
where?: ConstraintPayload;
|
|
40
|
+
/** An OSLC query text, evaluated instead of the structured query. */
|
|
41
|
+
oslc?: string;
|
|
42
|
+
/** A query already decoded for the wire; passes through as written. */
|
|
43
|
+
query?: Query;
|
|
44
|
+
}
|
|
45
|
+
/** Translate a query, given as the standard's JSON or as keywords, to protobuf. */
|
|
46
|
+
export declare function buildQuery(options?: {
|
|
47
|
+
payload?: QueryPayload;
|
|
48
|
+
} & QueryForm): Query;
|
|
49
|
+
/** The elements a `QueryResponse` reports, as `QueryElement` records. */
|
|
50
|
+
export declare function elementsOf(response: QueryResponse): QueryElement[];
|