sysml-v2-lsp 0.37.0 → 0.39.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/CHANGELOG.md +21 -0
- package/README.md +23 -1
- package/dist/server/browserServerMain.js +308 -77
- package/dist/server/mcpServer.js +72 -9
- package/dist/server/server.js +286 -55
- package/package.json +35 -1
package/dist/server/server.js
CHANGED
|
@@ -118,28 +118,28 @@ var require_messages = __commonJS({
|
|
|
118
118
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
119
119
|
exports2.Message = exports2.NotificationType9 = exports2.NotificationType8 = exports2.NotificationType7 = exports2.NotificationType6 = exports2.NotificationType5 = exports2.NotificationType4 = exports2.NotificationType3 = exports2.NotificationType2 = exports2.NotificationType1 = exports2.NotificationType0 = exports2.NotificationType = exports2.RequestType9 = exports2.RequestType8 = exports2.RequestType7 = exports2.RequestType6 = exports2.RequestType5 = exports2.RequestType4 = exports2.RequestType3 = exports2.RequestType2 = exports2.RequestType1 = exports2.RequestType = exports2.RequestType0 = exports2.AbstractMessageSignature = exports2.ParameterStructures = exports2.ResponseError = exports2.ErrorCodes = void 0;
|
|
120
120
|
var is = require_is2();
|
|
121
|
-
var
|
|
122
|
-
(function(
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
})(
|
|
139
|
-
var
|
|
121
|
+
var ErrorCodes3;
|
|
122
|
+
(function(ErrorCodes4) {
|
|
123
|
+
ErrorCodes4.ParseError = -32700;
|
|
124
|
+
ErrorCodes4.InvalidRequest = -32600;
|
|
125
|
+
ErrorCodes4.MethodNotFound = -32601;
|
|
126
|
+
ErrorCodes4.InvalidParams = -32602;
|
|
127
|
+
ErrorCodes4.InternalError = -32603;
|
|
128
|
+
ErrorCodes4.jsonrpcReservedErrorRangeStart = -32099;
|
|
129
|
+
ErrorCodes4.serverErrorStart = -32099;
|
|
130
|
+
ErrorCodes4.MessageWriteError = -32099;
|
|
131
|
+
ErrorCodes4.MessageReadError = -32098;
|
|
132
|
+
ErrorCodes4.PendingResponseRejected = -32097;
|
|
133
|
+
ErrorCodes4.ConnectionInactive = -32096;
|
|
134
|
+
ErrorCodes4.ServerNotInitialized = -32002;
|
|
135
|
+
ErrorCodes4.UnknownErrorCode = -32001;
|
|
136
|
+
ErrorCodes4.jsonrpcReservedErrorRangeEnd = -32e3;
|
|
137
|
+
ErrorCodes4.serverErrorEnd = -32e3;
|
|
138
|
+
})(ErrorCodes3 || (exports2.ErrorCodes = ErrorCodes3 = {}));
|
|
139
|
+
var ResponseError3 = class _ResponseError extends Error {
|
|
140
140
|
constructor(code, message, data) {
|
|
141
141
|
super(message);
|
|
142
|
-
this.code = is.number(code) ? code :
|
|
142
|
+
this.code = is.number(code) ? code : ErrorCodes3.UnknownErrorCode;
|
|
143
143
|
this.data = data;
|
|
144
144
|
Object.setPrototypeOf(this, _ResponseError.prototype);
|
|
145
145
|
}
|
|
@@ -154,7 +154,7 @@ var require_messages = __commonJS({
|
|
|
154
154
|
return result;
|
|
155
155
|
}
|
|
156
156
|
};
|
|
157
|
-
exports2.ResponseError =
|
|
157
|
+
exports2.ResponseError = ResponseError3;
|
|
158
158
|
var ParameterStructures = class _ParameterStructures {
|
|
159
159
|
constructor(kind) {
|
|
160
160
|
this.kind = kind;
|
|
@@ -3552,8 +3552,8 @@ var require_main2 = __commonJS({
|
|
|
3552
3552
|
}
|
|
3553
3553
|
CodeDescription2.is = is;
|
|
3554
3554
|
})(CodeDescription || (exports3.CodeDescription = CodeDescription = {}));
|
|
3555
|
-
var
|
|
3556
|
-
(function(
|
|
3555
|
+
var Diagnostic7;
|
|
3556
|
+
(function(Diagnostic8) {
|
|
3557
3557
|
function create(range, message, severity, code, source, relatedInformation) {
|
|
3558
3558
|
var result = { range, message };
|
|
3559
3559
|
if (Is.defined(severity)) {
|
|
@@ -3570,14 +3570,14 @@ var require_main2 = __commonJS({
|
|
|
3570
3570
|
}
|
|
3571
3571
|
return result;
|
|
3572
3572
|
}
|
|
3573
|
-
|
|
3573
|
+
Diagnostic8.create = create;
|
|
3574
3574
|
function is(value) {
|
|
3575
3575
|
var _a;
|
|
3576
3576
|
var candidate = value;
|
|
3577
3577
|
return Is.defined(candidate) && Range6.is(candidate.range) && Is.string(candidate.message) && (Is.number(candidate.severity) || Is.undefined(candidate.severity)) && (Is.integer(candidate.code) || Is.string(candidate.code) || Is.undefined(candidate.code)) && (Is.undefined(candidate.codeDescription) || Is.string((_a = candidate.codeDescription) === null || _a === void 0 ? void 0 : _a.href)) && (Is.string(candidate.source) || Is.undefined(candidate.source)) && (Is.undefined(candidate.relatedInformation) || Is.typedArray(candidate.relatedInformation, DiagnosticRelatedInformation.is));
|
|
3578
3578
|
}
|
|
3579
|
-
|
|
3580
|
-
})(
|
|
3579
|
+
Diagnostic8.is = is;
|
|
3580
|
+
})(Diagnostic7 || (exports3.Diagnostic = Diagnostic7 = {}));
|
|
3581
3581
|
var Command;
|
|
3582
3582
|
(function(Command2) {
|
|
3583
3583
|
function create(title, command) {
|
|
@@ -4362,7 +4362,7 @@ var require_main2 = __commonJS({
|
|
|
4362
4362
|
CodeActionContext2.create = create;
|
|
4363
4363
|
function is(value) {
|
|
4364
4364
|
var candidate = value;
|
|
4365
|
-
return Is.defined(candidate) && Is.typedArray(candidate.diagnostics,
|
|
4365
|
+
return Is.defined(candidate) && Is.typedArray(candidate.diagnostics, Diagnostic7.is) && (candidate.only === void 0 || Is.typedArray(candidate.only, Is.string)) && (candidate.triggerKind === void 0 || candidate.triggerKind === CodeActionTriggerKind.Invoked || candidate.triggerKind === CodeActionTriggerKind.Automatic);
|
|
4366
4366
|
}
|
|
4367
4367
|
CodeActionContext2.is = is;
|
|
4368
4368
|
})(CodeActionContext || (exports3.CodeActionContext = CodeActionContext = {}));
|
|
@@ -4387,7 +4387,7 @@ var require_main2 = __commonJS({
|
|
|
4387
4387
|
CodeAction3.create = create;
|
|
4388
4388
|
function is(value) {
|
|
4389
4389
|
var candidate = value;
|
|
4390
|
-
return candidate && Is.string(candidate.title) && (candidate.diagnostics === void 0 || Is.typedArray(candidate.diagnostics,
|
|
4390
|
+
return candidate && Is.string(candidate.title) && (candidate.diagnostics === void 0 || Is.typedArray(candidate.diagnostics, Diagnostic7.is)) && (candidate.kind === void 0 || Is.string(candidate.kind)) && (candidate.edit !== void 0 || candidate.command !== void 0) && (candidate.command === void 0 || Command.is(candidate.command)) && (candidate.isPreferred === void 0 || Is.boolean(candidate.isPreferred)) && (candidate.edit === void 0 || WorkspaceEdit4.is(candidate.edit));
|
|
4391
4391
|
}
|
|
4392
4392
|
CodeAction3.is = is;
|
|
4393
4393
|
})(CodeAction2 || (exports3.CodeAction = CodeAction2 = {}));
|
|
@@ -8880,7 +8880,7 @@ var require_node3 = __commonJS({
|
|
|
8880
8880
|
});
|
|
8881
8881
|
|
|
8882
8882
|
// server/src/server.ts
|
|
8883
|
-
var
|
|
8883
|
+
var import_node15 = __toESM(require_node3());
|
|
8884
8884
|
var fs = __toESM(require("node:fs"));
|
|
8885
8885
|
var path2 = __toESM(require("node:path"));
|
|
8886
8886
|
var import_node_url2 = require("node:url");
|
|
@@ -124358,6 +124358,13 @@ var DocumentManager = class {
|
|
|
124358
124358
|
* indexed yet" apart from "genuinely doesn't exist".
|
|
124359
124359
|
*/
|
|
124360
124360
|
workspaceScanComplete = true;
|
|
124361
|
+
/**
|
|
124362
|
+
* Last version given to a stand-in text by `withTexts`. Caches keyed by
|
|
124363
|
+
* version assume one text per uri and version, so each stand-in gets a
|
|
124364
|
+
* version outside the LSP integer range (LSP 3.17, base types).
|
|
124365
|
+
* These internal positive versions are never sent to the client.
|
|
124366
|
+
*/
|
|
124367
|
+
temporaryVersion = 2 ** 31 - 1;
|
|
124361
124368
|
/**
|
|
124362
124369
|
* Parse a document and cache the result.
|
|
124363
124370
|
* Returns the cached result if the content hasn't changed.
|
|
@@ -124561,6 +124568,35 @@ var DocumentManager = class {
|
|
|
124561
124568
|
this.wsSymbolTable.removeUri(uri);
|
|
124562
124569
|
this.wsBuiltVersions.delete(uri);
|
|
124563
124570
|
}
|
|
124571
|
+
/**
|
|
124572
|
+
* Runs `fn` with each text standing in for the document at its uri (or
|
|
124573
|
+
* added as a new document), all at once, then restores the previous
|
|
124574
|
+
* state. `fn` must be synchronous: no other request can run in between,
|
|
124575
|
+
* so no other request ever sees the temporary texts. Every text is
|
|
124576
|
+
* parsed before anything changes. The stand-ins get versions no real
|
|
124577
|
+
* document has, so caches keyed by version never confuse them with the
|
|
124578
|
+
* real documents.
|
|
124579
|
+
*/
|
|
124580
|
+
withTexts(documents2, fn) {
|
|
124581
|
+
if (!Number.isSafeInteger(this.temporaryVersion + documents2.length)) {
|
|
124582
|
+
throw new RangeError("Temporary document version space exhausted.");
|
|
124583
|
+
}
|
|
124584
|
+
const parsed = documents2.map(({ uri, text }) => ({ uri, text, result: parseDocument(text) }));
|
|
124585
|
+
const previous = new Map(parsed.map(({ uri }) => [uri, this.cache.get(uri)]));
|
|
124586
|
+
for (const { uri, text, result } of parsed) {
|
|
124587
|
+
this.cache.set(uri, { version: ++this.temporaryVersion, text, result, needsParse: false });
|
|
124588
|
+
}
|
|
124589
|
+
try {
|
|
124590
|
+
return fn();
|
|
124591
|
+
} finally {
|
|
124592
|
+
for (const [uri, entry] of previous) {
|
|
124593
|
+
if (entry) this.cache.set(uri, entry);
|
|
124594
|
+
else this.cache.delete(uri);
|
|
124595
|
+
this.wsSymbolTable.removeUri(uri);
|
|
124596
|
+
this.wsBuiltVersions.delete(uri);
|
|
124597
|
+
}
|
|
124598
|
+
}
|
|
124599
|
+
}
|
|
124564
124600
|
/**
|
|
124565
124601
|
* Get all cached URIs.
|
|
124566
124602
|
*/
|
|
@@ -125382,12 +125418,19 @@ var MAX_NAMESPACE_NESTING_DEPTH = 64;
|
|
|
125382
125418
|
function findConflictedQualifiedNames(allSymbols) {
|
|
125383
125419
|
return groupConflicts(allSymbols.filter((s) => s.qualifiedName !== void 0), (s) => s.qualifiedName);
|
|
125384
125420
|
}
|
|
125421
|
+
function memberNamesOf(symbol) {
|
|
125422
|
+
return symbol.shortName && symbol.shortName !== symbol.name ? [symbol.name, symbol.shortName] : [symbol.name];
|
|
125423
|
+
}
|
|
125385
125424
|
function findConflictingDeclarations(allSymbols) {
|
|
125386
125425
|
const conflicting = /* @__PURE__ */ new Map();
|
|
125387
125426
|
const add = (groups) => {
|
|
125388
|
-
for (const group of groups
|
|
125427
|
+
for (const group of groups) {
|
|
125428
|
+
for (const s of group) {
|
|
125429
|
+
conflicting.set(s, [.../* @__PURE__ */ new Set([...conflicting.get(s) ?? [], ...group])]);
|
|
125430
|
+
}
|
|
125431
|
+
}
|
|
125389
125432
|
};
|
|
125390
|
-
add(findConflictedQualifiedNames(allSymbols));
|
|
125433
|
+
add(findConflictedQualifiedNames(allSymbols).values());
|
|
125391
125434
|
const membersOfAnonymous = allSymbols.filter((s) => s.qualifiedName === void 0 && !isAnonymous(s) && s.parentId !== void 0);
|
|
125392
125435
|
const byOwner = /* @__PURE__ */ new Map();
|
|
125393
125436
|
for (const s of membersOfAnonymous) {
|
|
@@ -125395,13 +125438,33 @@ function findConflictingDeclarations(allSymbols) {
|
|
|
125395
125438
|
list.push(s);
|
|
125396
125439
|
byOwner.set(s.parentId, list);
|
|
125397
125440
|
}
|
|
125398
|
-
for (const members of byOwner.values()) add(groupConflicts(members, (s) => s.name));
|
|
125441
|
+
for (const members of byOwner.values()) add(groupConflicts(members, (s) => s.name).values());
|
|
125442
|
+
add([...findConflictingShortNames(allSymbols).values()].map((group) => group.symbols));
|
|
125399
125443
|
return conflicting;
|
|
125400
125444
|
}
|
|
125445
|
+
function findConflictingShortNames(allSymbols) {
|
|
125446
|
+
const byId = new Map(allSymbols.map((s) => [s.symbolId, s]));
|
|
125447
|
+
const entries = [];
|
|
125448
|
+
const keysWithShortName = /* @__PURE__ */ new Set();
|
|
125449
|
+
for (const s of allSymbols) {
|
|
125450
|
+
if (isAnonymous(s)) continue;
|
|
125451
|
+
const owner = s.parentId ? byId.get(s.parentId) : void 0;
|
|
125452
|
+
const namespace = owner === void 0 ? "q:" : owner.qualifiedName !== void 0 ? `q:${owner.qualifiedName}` : `id:${owner.symbolId}`;
|
|
125453
|
+
for (const name of memberNamesOf(s)) {
|
|
125454
|
+
const key = `${namespace}\0${name}`;
|
|
125455
|
+
entries.push({ symbol: s, key });
|
|
125456
|
+
if (name === s.shortName) keysWithShortName.add(key);
|
|
125457
|
+
}
|
|
125458
|
+
}
|
|
125459
|
+
const groups = groupKeyedConflicts(entries.filter((e) => keysWithShortName.has(e.key)));
|
|
125460
|
+
return new Map([...groups].map(([key, symbols]) => [key, { name: key.slice(key.indexOf("\0") + 1), symbols }]));
|
|
125461
|
+
}
|
|
125401
125462
|
function groupConflicts(symbols, keyOf) {
|
|
125463
|
+
return groupKeyedConflicts(symbols.map((symbol) => ({ symbol, key: keyOf(symbol) })));
|
|
125464
|
+
}
|
|
125465
|
+
function groupKeyedConflicts(entries) {
|
|
125402
125466
|
const byKeyAndKind = /* @__PURE__ */ new Map();
|
|
125403
|
-
for (const s of
|
|
125404
|
-
const key = keyOf(s);
|
|
125467
|
+
for (const { symbol: s, key } of entries) {
|
|
125405
125468
|
let byKind = byKeyAndKind.get(key);
|
|
125406
125469
|
if (!byKind) {
|
|
125407
125470
|
byKind = /* @__PURE__ */ new Map();
|
|
@@ -125473,7 +125536,13 @@ function buildSymbolIndexes(allSymbols) {
|
|
|
125473
125536
|
for (const s of allSymbols) {
|
|
125474
125537
|
byId.set(s.symbolId, s);
|
|
125475
125538
|
}
|
|
125476
|
-
const
|
|
125539
|
+
const clashingShortNames = /* @__PURE__ */ new Map();
|
|
125540
|
+
for (const { name, symbols } of findConflictingShortNames(allSymbols).values()) {
|
|
125541
|
+
const clashing = clashingShortNames.get(name) ?? /* @__PURE__ */ new Set();
|
|
125542
|
+
for (const s of symbols) clashing.add(s);
|
|
125543
|
+
clashingShortNames.set(name, clashing);
|
|
125544
|
+
}
|
|
125545
|
+
const indexes = { byName, byParent, byQualifiedName, byId, definitionsByName, portsByName, clashingShortNames };
|
|
125477
125546
|
for (const s of allSymbols) {
|
|
125478
125547
|
if (isAnonymous(s)) continue;
|
|
125479
125548
|
const nameList = byName.get(s.name) ?? [];
|
|
@@ -125562,6 +125631,16 @@ var NamespaceResolver = class {
|
|
|
125562
125631
|
resolveNameIn(namespace, name, indexes) {
|
|
125563
125632
|
return this.resolveQualifiedNameFrom(namespace ? namespaceKeyOf(namespace) : "", name, indexes);
|
|
125564
125633
|
}
|
|
125634
|
+
/** Resolve an editor reference without losing the reason a name is unresolved. */
|
|
125635
|
+
resolveReferenceIn(namespace, name, indexes) {
|
|
125636
|
+
return this.resolveQualifiedReferenceFrom(namespace ? namespaceKeyOf(namespace) : "", name, indexes);
|
|
125637
|
+
}
|
|
125638
|
+
/** Resolve a public qualified or feature-path member, without enclosing-scope fallback. */
|
|
125639
|
+
resolveMemberReference(owner, name, indexes) {
|
|
125640
|
+
const members = this.getResolvedMembers(namespaceKeyOf(owner), indexes).get(name);
|
|
125641
|
+
if (members && this.isAmbiguous(name, members, indexes)) return { ambiguous: true };
|
|
125642
|
+
return this.referenceTo(members?.find((member) => member.visibility === "public")?.symbol, indexes);
|
|
125643
|
+
}
|
|
125565
125644
|
/**
|
|
125566
125645
|
* Resolve a (possibly qualified) name to its symbol per §7.5.1, searching
|
|
125567
125646
|
* outward from namespace `start` and its enclosing namespaces (its own resolved
|
|
@@ -125573,28 +125652,48 @@ var NamespaceResolver = class {
|
|
|
125573
125652
|
* its own enclosing package already imported, per §7.5.1/§7.5.3).
|
|
125574
125653
|
*/
|
|
125575
125654
|
resolveQualifiedNameFrom(start, name, indexes) {
|
|
125655
|
+
return this.resolveQualifiedReferenceFrom(start, name, indexes).symbol;
|
|
125656
|
+
}
|
|
125657
|
+
resolveQualifiedReferenceFrom(start, name, indexes) {
|
|
125576
125658
|
const [first, ...rest] = splitQualifiedName(name);
|
|
125577
125659
|
let resolved;
|
|
125578
125660
|
for (const ancestor of this.namespaceAncestorsOf(start, indexes)) {
|
|
125579
125661
|
const candidates = this.getResolvedMembers(ancestor, indexes).get(first);
|
|
125580
125662
|
if (candidates && candidates.length > 0) {
|
|
125663
|
+
if (this.isAmbiguous(first, candidates, indexes)) return { ambiguous: true };
|
|
125581
125664
|
resolved = candidates[0].symbol;
|
|
125582
125665
|
break;
|
|
125583
125666
|
}
|
|
125584
125667
|
}
|
|
125585
|
-
if (resolved === void 0) return
|
|
125668
|
+
if (resolved === void 0) return { ambiguous: false };
|
|
125586
125669
|
const isWithinStart = (namespace) => this.namespaceAncestorsOf(start, indexes).has(namespace);
|
|
125587
125670
|
for (const segment of rest) {
|
|
125588
125671
|
const owner = resolved;
|
|
125589
125672
|
const ownerKey = namespaceKeyOf(owner);
|
|
125590
125673
|
const members = this.getResolvedMembers(ownerKey, indexes).get(segment);
|
|
125674
|
+
if (members && this.isAmbiguous(segment, members, indexes)) return { ambiguous: true };
|
|
125591
125675
|
const visibleMember = members?.find(
|
|
125592
125676
|
(m2) => m2.visibility === "public" || isWithinStart(ownerKey) || m2.visibility === "protected" && this.isProtectedVisibleFrom(start, owner, indexes)
|
|
125593
125677
|
);
|
|
125594
|
-
if (!visibleMember) return
|
|
125678
|
+
if (!visibleMember) return { ambiguous: false };
|
|
125595
125679
|
resolved = visibleMember.symbol;
|
|
125596
125680
|
}
|
|
125597
|
-
return resolved
|
|
125681
|
+
return this.referenceTo(resolved, indexes);
|
|
125682
|
+
}
|
|
125683
|
+
referenceTo(resolved, indexes) {
|
|
125684
|
+
if (!resolved) return { ambiguous: false };
|
|
125685
|
+
const symbol = resolved.qualifiedName !== void 0 ? indexes.byQualifiedName.get(resolved.qualifiedName) : resolved;
|
|
125686
|
+
return { symbol, ambiguous: symbol === void 0 };
|
|
125687
|
+
}
|
|
125688
|
+
/**
|
|
125689
|
+
* Whether `name` names more than one of `candidates` that clash on it
|
|
125690
|
+
* through a short name (`SymbolIndexes.clashingShortNames`), so it can't
|
|
125691
|
+
* be resolved to either (KerML 7.2.5.2). Like a conflicted qualifiedName,
|
|
125692
|
+
* it doesn't fall through to an enclosing namespace's member of that name.
|
|
125693
|
+
*/
|
|
125694
|
+
isAmbiguous(name, candidates, indexes) {
|
|
125695
|
+
const clashing = indexes.clashingShortNames.get(name);
|
|
125696
|
+
return clashing !== void 0 && candidates.filter((c) => clashing.has(c.symbol)).length > 1;
|
|
125598
125697
|
}
|
|
125599
125698
|
/**
|
|
125600
125699
|
* §7.5.3's protected-import exception: "A visibility of protected is the
|
|
@@ -128297,9 +128396,11 @@ var NameReferences = class {
|
|
|
128297
128396
|
if (target && !path3.qualifiedNames.some((name) => name.segments.some((segment) => segment.name === target.name || segment.name === target.shortName))) continue;
|
|
128298
128397
|
const namespace = namespaces.find((ns) => ns.body < path3.start && path3.end <= ns.end);
|
|
128299
128398
|
let receiver;
|
|
128399
|
+
let receiverAmbiguous = false;
|
|
128300
128400
|
for (let group = 0; group < path3.qualifiedNames.length; group++) {
|
|
128301
128401
|
const qualified = path3.qualifiedNames[group];
|
|
128302
128402
|
let resolved;
|
|
128403
|
+
let ambiguous = false;
|
|
128303
128404
|
for (let index2 = 0; index2 < qualified.segments.length; index2++) {
|
|
128304
128405
|
const segment = qualified.segments[index2];
|
|
128305
128406
|
const range = import_node4.Range.create(doc.positionAt(segment.start), doc.positionAt(segment.end));
|
|
@@ -128308,17 +128409,27 @@ var NameReferences = class {
|
|
|
128308
128409
|
while (before >= 0 && /\s/.test(text[before])) before--;
|
|
128309
128410
|
while (after < text.length && /\s/.test(text[after])) after++;
|
|
128310
128411
|
const declaration = symbols.find((symbol) => !isAnonymous(symbol) && (symbol.selectionRange.start.line === range.start.line && symbol.selectionRange.start.character === range.start.character && symbol.selectionRange.end.character === range.end.character || symbol.shortName === segment.name && text[before] === "<" && text[after] === ">" && doc.offsetAt(symbol.range.start) <= segment.start && segment.end < doc.offsetAt(symbol.selectionRange.start)));
|
|
128311
|
-
if (declaration)
|
|
128312
|
-
|
|
128313
|
-
|
|
128412
|
+
if (declaration) {
|
|
128413
|
+
resolved = declaration;
|
|
128414
|
+
ambiguous = false;
|
|
128415
|
+
} else if (index2 > 0) {
|
|
128416
|
+
if (resolved) {
|
|
128417
|
+
const result = this.resolver.resolveMemberReference(resolved, segment.name, this.indexes);
|
|
128418
|
+
resolved = result.symbol;
|
|
128419
|
+
ambiguous = result.ambiguous;
|
|
128420
|
+
}
|
|
128314
128421
|
} else if (group > 0) {
|
|
128315
|
-
|
|
128422
|
+
const result = receiver ? this.resolveFeature(receiver, segment.name) : { ambiguous: receiverAmbiguous };
|
|
128423
|
+
resolved = result.symbol;
|
|
128424
|
+
ambiguous = result.ambiguous;
|
|
128316
128425
|
} else {
|
|
128317
|
-
|
|
128426
|
+
const result = this.resolver.resolveReferenceIn(
|
|
128318
128427
|
namespace?.symbol,
|
|
128319
128428
|
joinQualifiedName([segment.name]),
|
|
128320
128429
|
this.indexes
|
|
128321
128430
|
);
|
|
128431
|
+
resolved = result.symbol;
|
|
128432
|
+
ambiguous = result.ambiguous;
|
|
128322
128433
|
}
|
|
128323
128434
|
if (cursor !== void 0 && (cursor < segment.start || cursor > segment.end)) continue;
|
|
128324
128435
|
if (target && segment.name !== target.name && segment.name !== target.shortName) continue;
|
|
@@ -128328,10 +128439,12 @@ var NameReferences = class {
|
|
|
128328
128439
|
name: segment.name,
|
|
128329
128440
|
qualifiedName: index2 === qualified.segments.length - 1 ? qualified.name : segment.name,
|
|
128330
128441
|
symbol: resolved,
|
|
128331
|
-
isDeclaration: declaration !== void 0
|
|
128442
|
+
isDeclaration: declaration !== void 0,
|
|
128443
|
+
isAmbiguous: ambiguous
|
|
128332
128444
|
});
|
|
128333
128445
|
}
|
|
128334
128446
|
receiver = resolved;
|
|
128447
|
+
receiverAmbiguous = ambiguous;
|
|
128335
128448
|
}
|
|
128336
128449
|
}
|
|
128337
128450
|
return refs;
|
|
@@ -128343,14 +128456,14 @@ var NameReferences = class {
|
|
|
128343
128456
|
const owner = queue[index2];
|
|
128344
128457
|
if (visited.has(owner)) continue;
|
|
128345
128458
|
visited.add(owner);
|
|
128346
|
-
const member = this.resolver.
|
|
128347
|
-
if (member) return member;
|
|
128459
|
+
const member = this.resolver.resolveMemberReference(owner, name, this.indexes);
|
|
128460
|
+
if (member.symbol || member.ambiguous) return member;
|
|
128348
128461
|
for (const typeName of owner.typeNames) {
|
|
128349
128462
|
const type = this.resolver.resolveNameFrom(owner, typeName, this.indexes);
|
|
128350
128463
|
if (type && !visited.has(type)) queue.push(type);
|
|
128351
128464
|
}
|
|
128352
128465
|
}
|
|
128353
|
-
return
|
|
128466
|
+
return { ambiguous: false };
|
|
128354
128467
|
}
|
|
128355
128468
|
};
|
|
128356
128469
|
|
|
@@ -128367,6 +128480,7 @@ var DefinitionProvider = class {
|
|
|
128367
128480
|
}
|
|
128368
128481
|
const wsSymbolTable = this.documentManager.getWorkspaceSymbolTable();
|
|
128369
128482
|
const reference = new NameReferences(this.documentManager).at(params.textDocument.uri, params.position);
|
|
128483
|
+
if (reference?.isAmbiguous) return null;
|
|
128370
128484
|
if (reference?.symbol && !reference.isDeclaration) {
|
|
128371
128485
|
return { uri: reference.symbol.uri, range: reference.symbol.selectionRange };
|
|
128372
128486
|
}
|
|
@@ -128981,6 +129095,7 @@ var HoverProvider = class {
|
|
|
128981
129095
|
}
|
|
128982
129096
|
const text = this.documentManager.getText(params.textDocument.uri);
|
|
128983
129097
|
const reference = new NameReferences(this.documentManager).at(params.textDocument.uri, params.position);
|
|
129098
|
+
if (reference?.isAmbiguous) return null;
|
|
128984
129099
|
const word = reference?.qualifiedName ?? (text ? this.getWordAtPosition(text, params.position.line, params.position.character) : void 0);
|
|
128985
129100
|
if (word && word.includes("::") && !reference?.symbol) {
|
|
128986
129101
|
const libHover = this.buildLibraryHover(word);
|
|
@@ -131036,6 +131151,115 @@ var SemanticValidator = class _SemanticValidator {
|
|
|
131036
131151
|
}
|
|
131037
131152
|
};
|
|
131038
131153
|
|
|
131154
|
+
// server/src/providers/textValidationProvider.ts
|
|
131155
|
+
var import_node14 = __toESM(require_node3());
|
|
131156
|
+
var DEFAULT_TEXT_VALIDATION_SETTINGS = {
|
|
131157
|
+
enabled: false,
|
|
131158
|
+
maxDocuments: 5,
|
|
131159
|
+
maxLines: 200,
|
|
131160
|
+
maxCharacters: 8192,
|
|
131161
|
+
maxTotalCharacters: 16384
|
|
131162
|
+
};
|
|
131163
|
+
function readTextValidationSettings(section) {
|
|
131164
|
+
const raw = typeof section === "object" && section !== null ? section : {};
|
|
131165
|
+
const limit = (value, fallback) => Number.isSafeInteger(value) && value > 0 ? value : fallback;
|
|
131166
|
+
return {
|
|
131167
|
+
enabled: raw.enabled === true,
|
|
131168
|
+
maxDocuments: limit(raw.maxDocuments, DEFAULT_TEXT_VALIDATION_SETTINGS.maxDocuments),
|
|
131169
|
+
maxLines: limit(raw.maxLines, DEFAULT_TEXT_VALIDATION_SETTINGS.maxLines),
|
|
131170
|
+
maxCharacters: limit(raw.maxCharacters, DEFAULT_TEXT_VALIDATION_SETTINGS.maxCharacters),
|
|
131171
|
+
maxTotalCharacters: limit(raw.maxTotalCharacters, DEFAULT_TEXT_VALIDATION_SETTINGS.maxTotalCharacters)
|
|
131172
|
+
};
|
|
131173
|
+
}
|
|
131174
|
+
var TextValidationProvider = class {
|
|
131175
|
+
/**
|
|
131176
|
+
* `isReported` filters diagnostics as the server does before
|
|
131177
|
+
* publishing them (`sysml.validation.disabledCodes`), so a text gets
|
|
131178
|
+
* exactly what it would get as an open document.
|
|
131179
|
+
*/
|
|
131180
|
+
constructor(documentManager2, semanticValidator2, isReported2 = () => true) {
|
|
131181
|
+
this.documentManager = documentManager2;
|
|
131182
|
+
this.semanticValidator = semanticValidator2;
|
|
131183
|
+
this.isReported = isReported2;
|
|
131184
|
+
}
|
|
131185
|
+
documentManager;
|
|
131186
|
+
semanticValidator;
|
|
131187
|
+
isReported;
|
|
131188
|
+
settings = { ...DEFAULT_TEXT_VALIDATION_SETTINGS };
|
|
131189
|
+
/** Applies the client's settings to the requests that follow. */
|
|
131190
|
+
configure(settings) {
|
|
131191
|
+
this.settings = { ...settings };
|
|
131192
|
+
}
|
|
131193
|
+
/**
|
|
131194
|
+
* The diagnostics each text would get as an open document, with all
|
|
131195
|
+
* texts in place at the same time. Answers `MethodNotFound` while
|
|
131196
|
+
* disabled, and `InvalidParams` for malformed parameters or parameters
|
|
131197
|
+
* over a limit.
|
|
131198
|
+
*/
|
|
131199
|
+
validate(params) {
|
|
131200
|
+
if (!this.settings.enabled) {
|
|
131201
|
+
throw new import_node14.ResponseError(
|
|
131202
|
+
import_node14.ErrorCodes.MethodNotFound,
|
|
131203
|
+
"sysml/validateText is experimental and disabled: set sysml.experimental.validateText.enabled to true."
|
|
131204
|
+
);
|
|
131205
|
+
}
|
|
131206
|
+
const documents2 = this.checkDocuments(params?.documents);
|
|
131207
|
+
const known = documents2.map((document) => ({ uri: this.knownSpelling(document.uri), text: document.text }));
|
|
131208
|
+
const diagnostics = this.documentManager.withTexts(known, () => known.map(({ uri }) => this.diagnose(uri)));
|
|
131209
|
+
return { documents: documents2.map((document, index2) => ({ uri: document.uri, diagnostics: diagnostics[index2] })) };
|
|
131210
|
+
}
|
|
131211
|
+
/** `documents` checked: a non-empty array of `{ uri, text }` within the limits, each naming a different document. */
|
|
131212
|
+
checkDocuments(documents2) {
|
|
131213
|
+
if (!Array.isArray(documents2) || documents2.length === 0) invalid('"documents" must be a non-empty array of { uri, text }.');
|
|
131214
|
+
const { maxDocuments, maxLines, maxCharacters, maxTotalCharacters } = this.settings;
|
|
131215
|
+
if (documents2.length > maxDocuments) {
|
|
131216
|
+
invalid(`${documents2.length} documents, more than the ${maxDocuments} allowed (sysml.experimental.validateText.maxDocuments).`);
|
|
131217
|
+
}
|
|
131218
|
+
const checked = documents2;
|
|
131219
|
+
let totalCharacters = 0;
|
|
131220
|
+
checked.forEach((document, index2) => {
|
|
131221
|
+
if (typeof document?.text !== "string") invalid(`documents[${index2}] needs "text", the SysML text to validate.`);
|
|
131222
|
+
if (document.text.length > maxCharacters) {
|
|
131223
|
+
invalid(`documents[${index2}] has ${document.text.length} characters, more than the ${maxCharacters} allowed (sysml.experimental.validateText.maxCharacters).`);
|
|
131224
|
+
}
|
|
131225
|
+
totalCharacters += document.text.length;
|
|
131226
|
+
if (totalCharacters > maxTotalCharacters) {
|
|
131227
|
+
invalid(`${totalCharacters} total characters, more than the ${maxTotalCharacters} allowed (sysml.experimental.validateText.maxTotalCharacters).`);
|
|
131228
|
+
}
|
|
131229
|
+
const lines = lineCount(document.text);
|
|
131230
|
+
if (lines > maxLines) {
|
|
131231
|
+
invalid(`documents[${index2}] has ${lines} lines, more than the ${maxLines} allowed (sysml.experimental.validateText.maxLines).`);
|
|
131232
|
+
}
|
|
131233
|
+
if (!isUri(document.uri)) invalid(`documents[${index2}] needs "uri", the document the text is the content of.`);
|
|
131234
|
+
const earlier = checked.findIndex((other) => isSameDocumentUri(other.uri, document.uri));
|
|
131235
|
+
if (earlier !== index2) invalid(`documents[${earlier}] and documents[${index2}] name the same document.`);
|
|
131236
|
+
});
|
|
131237
|
+
return checked;
|
|
131238
|
+
}
|
|
131239
|
+
/** The syntax, keyword and semantic diagnostics of the document at `uri`, as published for an open document. */
|
|
131240
|
+
diagnose(uri) {
|
|
131241
|
+
const diagnostics = new DiagnosticsProvider(this.documentManager).getDiagnostics(uri);
|
|
131242
|
+
const parseResult = this.documentManager.get(uri);
|
|
131243
|
+
if (parseResult) diagnostics.push(...validateKeywords(parseResult));
|
|
131244
|
+
diagnostics.push(...this.semanticValidator.validate(uri));
|
|
131245
|
+
return diagnostics.filter(this.isReported);
|
|
131246
|
+
}
|
|
131247
|
+
/** The spelling under which the server knows the document `uri` names, else `uri` itself (see `isSameDocumentUri`). */
|
|
131248
|
+
knownSpelling(uri) {
|
|
131249
|
+
return this.documentManager.getUris().find((known) => isSameDocumentUri(known, uri)) ?? uri;
|
|
131250
|
+
}
|
|
131251
|
+
};
|
|
131252
|
+
function lineCount(text) {
|
|
131253
|
+
const breaks = text.match(/\r\n|\r|\n/g)?.length ?? 0;
|
|
131254
|
+
return text === "" || /[\r\n]$/.test(text) ? breaks : breaks + 1;
|
|
131255
|
+
}
|
|
131256
|
+
function isUri(value) {
|
|
131257
|
+
return typeof value === "string" && value.trim() !== "";
|
|
131258
|
+
}
|
|
131259
|
+
function invalid(message) {
|
|
131260
|
+
throw new import_node14.ResponseError(import_node14.ErrorCodes.InvalidParams, `sysml/validateText: ${message}`);
|
|
131261
|
+
}
|
|
131262
|
+
|
|
131039
131263
|
// server/src/utils/fileDiscovery.ts
|
|
131040
131264
|
var fsp = __toESM(require("node:fs/promises"));
|
|
131041
131265
|
var path = __toESM(require("node:path"));
|
|
@@ -131110,7 +131334,7 @@ function toFsPath(uri) {
|
|
|
131110
131334
|
return void 0;
|
|
131111
131335
|
}
|
|
131112
131336
|
var connection = createServerConnection();
|
|
131113
|
-
var documents = new
|
|
131337
|
+
var documents = new import_node15.TextDocuments(TextDocument);
|
|
131114
131338
|
var serverStartTime = Date.now();
|
|
131115
131339
|
var documentManager = new DocumentManager();
|
|
131116
131340
|
var modelProvider = new SysMLModelProvider(documentManager);
|
|
@@ -131127,6 +131351,7 @@ var renameProvider = new RenameProvider(documentManager);
|
|
|
131127
131351
|
var codeActionProvider = new CodeActionProvider(documentManager);
|
|
131128
131352
|
var formattingProvider = new FormattingProvider(documents);
|
|
131129
131353
|
var semanticValidator = new SemanticValidator(documentManager);
|
|
131354
|
+
var textValidationProvider = new TextValidationProvider(documentManager, semanticValidator, isReported);
|
|
131130
131355
|
hoverProvider.setSemanticValidator(semanticValidator);
|
|
131131
131356
|
var hasConfigurationCapability = false;
|
|
131132
131357
|
var hasWorkspaceFolderCapability = false;
|
|
@@ -131138,11 +131363,11 @@ function rootsOf(folderUris) {
|
|
|
131138
131363
|
var isWorkspaceFile = false;
|
|
131139
131364
|
var preloadOnOpen = "workspaceOnly";
|
|
131140
131365
|
var disabledDiagnosticCodes = /* @__PURE__ */ new Set();
|
|
131366
|
+
function isReported(diagnostic) {
|
|
131367
|
+
return diagnostic.code === void 0 || !disabledDiagnosticCodes.has(String(diagnostic.code));
|
|
131368
|
+
}
|
|
131141
131369
|
function publishDiagnostics(uri, diagnostics) {
|
|
131142
|
-
connection.sendDiagnostics({
|
|
131143
|
-
uri,
|
|
131144
|
-
diagnostics: diagnostics.filter((diagnostic) => diagnostic.code === void 0 || !disabledDiagnosticCodes.has(String(diagnostic.code)))
|
|
131145
|
-
});
|
|
131370
|
+
connection.sendDiagnostics({ uri, diagnostics: diagnostics.filter(isReported) });
|
|
131146
131371
|
}
|
|
131147
131372
|
var skipDirs = new Set(DEFAULT_SKIP_DIRS);
|
|
131148
131373
|
var serverReady = false;
|
|
@@ -131275,7 +131500,7 @@ connection.onInitialize((params) => {
|
|
|
131275
131500
|
};
|
|
131276
131501
|
const result = {
|
|
131277
131502
|
capabilities: {
|
|
131278
|
-
textDocumentSync:
|
|
131503
|
+
textDocumentSync: import_node15.TextDocumentSyncKind.Incremental,
|
|
131279
131504
|
// Completion
|
|
131280
131505
|
completionProvider: {
|
|
131281
131506
|
resolveProvider: true,
|
|
@@ -131303,7 +131528,7 @@ connection.onInitialize((params) => {
|
|
|
131303
131528
|
// Code actions (quick fixes)
|
|
131304
131529
|
codeActionProvider: {
|
|
131305
131530
|
codeActionKinds: [
|
|
131306
|
-
|
|
131531
|
+
import_node15.CodeActionKind.QuickFix
|
|
131307
131532
|
]
|
|
131308
131533
|
},
|
|
131309
131534
|
// Document formatting
|
|
@@ -131324,7 +131549,7 @@ connection.onInitialize((params) => {
|
|
|
131324
131549
|
connection.onInitialized(async () => {
|
|
131325
131550
|
if (hasConfigurationCapability) {
|
|
131326
131551
|
connection.client.register(
|
|
131327
|
-
|
|
131552
|
+
import_node15.DidChangeConfigurationNotification.type,
|
|
131328
131553
|
void 0
|
|
131329
131554
|
);
|
|
131330
131555
|
}
|
|
@@ -131385,6 +131610,8 @@ async function pullSettings() {
|
|
|
131385
131610
|
const validation = await connection.workspace.getConfiguration("sysml.validation");
|
|
131386
131611
|
const codes = validation?.disabledCodes;
|
|
131387
131612
|
disabledDiagnosticCodes = new Set(Array.isArray(codes) ? codes.filter((code) => typeof code === "string") : []);
|
|
131613
|
+
const experimental = await connection.workspace.getConfiguration("sysml.experimental");
|
|
131614
|
+
textValidationProvider.configure(readTextValidationSettings(experimental?.validateText));
|
|
131388
131615
|
}
|
|
131389
131616
|
function applySettings(config) {
|
|
131390
131617
|
if (!config) return;
|
|
@@ -131738,6 +131965,10 @@ connection.onRequest("sysml/elementLookup", async (params) => {
|
|
|
131738
131965
|
await initialization;
|
|
131739
131966
|
return elementLookupProvider.elementLookup(params);
|
|
131740
131967
|
});
|
|
131968
|
+
connection.onRequest("sysml/validateText", async (params) => {
|
|
131969
|
+
await initialization;
|
|
131970
|
+
return textValidationProvider.validate(params);
|
|
131971
|
+
});
|
|
131741
131972
|
connection.onRequest("sysml/serverStats", () => {
|
|
131742
131973
|
const mem = typeof process !== "undefined" && typeof process.memoryUsage === "function" ? process.memoryUsage() : { heapUsed: 0, heapTotal: 0, rss: 0, external: 0 };
|
|
131743
131974
|
const toMB = (bytes) => Math.round(bytes / 1024 / 1024);
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "sysml-v2-lsp",
|
|
3
3
|
"displayName": "SysML v2 Language Server",
|
|
4
4
|
"description": "Language Server Protocol implementation for SysML v2, powered by ANTLR4",
|
|
5
|
-
"version": "0.
|
|
5
|
+
"version": "0.39.0",
|
|
6
6
|
"publisher": "JamieD",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"repository": {
|
|
@@ -96,6 +96,40 @@
|
|
|
96
96
|
"default": [],
|
|
97
97
|
"description": "Diagnostic codes to suppress, such as missing-doc. Changes apply to open documents immediately."
|
|
98
98
|
},
|
|
99
|
+
"sysml.experimental.validateText.enabled": {
|
|
100
|
+
"scope": "window",
|
|
101
|
+
"type": "boolean",
|
|
102
|
+
"default": false,
|
|
103
|
+
"markdownDescription": "Experimental: answer the custom `sysml/validateText` request, which validates SysML text against the workspace model without opening a document or publishing diagnostics. The request is meant for tools that generate or edit SysML text."
|
|
104
|
+
},
|
|
105
|
+
"sysml.experimental.validateText.maxDocuments": {
|
|
106
|
+
"scope": "window",
|
|
107
|
+
"type": "integer",
|
|
108
|
+
"minimum": 1,
|
|
109
|
+
"default": 5,
|
|
110
|
+
"markdownDescription": "Experimental: the most documents one `sysml/validateText` request may validate. Requests with more are rejected."
|
|
111
|
+
},
|
|
112
|
+
"sysml.experimental.validateText.maxLines": {
|
|
113
|
+
"scope": "window",
|
|
114
|
+
"type": "integer",
|
|
115
|
+
"minimum": 1,
|
|
116
|
+
"default": 200,
|
|
117
|
+
"markdownDescription": "Experimental: the most lines of code one document's text may have in a `sysml/validateText` request. Requests with a longer text are rejected. Character limits also apply."
|
|
118
|
+
},
|
|
119
|
+
"sysml.experimental.validateText.maxCharacters": {
|
|
120
|
+
"scope": "window",
|
|
121
|
+
"type": "integer",
|
|
122
|
+
"minimum": 1,
|
|
123
|
+
"default": 8192,
|
|
124
|
+
"markdownDescription": "Experimental: the most characters (UTF-16 code units) per document in a `sysml/validateText` request. Checked before parsing, including for single-line text."
|
|
125
|
+
},
|
|
126
|
+
"sysml.experimental.validateText.maxTotalCharacters": {
|
|
127
|
+
"scope": "window",
|
|
128
|
+
"type": "integer",
|
|
129
|
+
"minimum": 1,
|
|
130
|
+
"default": 16384,
|
|
131
|
+
"markdownDescription": "Experimental: the most characters (UTF-16 code units) across all documents in a `sysml/validateText` request. Checked before parsing."
|
|
132
|
+
},
|
|
99
133
|
"sysml.maxNumberOfProblems": {
|
|
100
134
|
"scope": "resource",
|
|
101
135
|
"type": "number",
|