sysml-v2-lsp 0.37.0 → 0.38.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 +12 -0
- package/README.md +23 -1
- package/dist/server/browserServerMain.js +211 -59
- package/dist/server/server.js +189 -37
- package/package.json +35 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [0.38.0]
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- Experimental LSP request `sysml/validateText`: validates texts against the workspace model without opening or publishing anything. Disabled by default. Enabled by `sysml.experimental.validateText.enabled`, limited by `maxDocuments` (5), `maxLines` (200), `maxCharacters` (8,192 per document), and `maxTotalCharacters` (16,384 per request). Character limits use UTF-16 code units and are checked before parsing.
|
|
10
|
+
- Benchmark suite for `sysml/validateText`.
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Keep temporary validation versions outside the LSP integer range so they
|
|
15
|
+
cannot reuse a real document's version or its cached diagnostics.
|
|
16
|
+
|
|
5
17
|
## [0.37.0]
|
|
6
18
|
|
|
7
19
|
### Fixed
|
package/README.md
CHANGED
|
@@ -40,6 +40,27 @@ usage names or unrelated same-named declarations. Completion and rename insert
|
|
|
40
40
|
the required quotes and escapes automatically; editor positions use UTF-16,
|
|
41
41
|
including after characters outside the Basic Multilingual Plane.
|
|
42
42
|
|
|
43
|
+
### Experimental text validation
|
|
44
|
+
|
|
45
|
+
`sysml/validateText` checks proposed document texts against the current workspace,
|
|
46
|
+
including unsaved documents, without opening documents or publishing diagnostics.
|
|
47
|
+
It is disabled by default. Enable `sysml.experimental.validateText.enabled` to use it.
|
|
48
|
+
Requests contain `documents`, an array of `{ uri, text }` entries. The response
|
|
49
|
+
contains each requested URI and its diagnostics, in request order.
|
|
50
|
+
|
|
51
|
+
The default limits are 5 documents, 200 lines per document, 8,192 characters per
|
|
52
|
+
document, and 16,384 characters across the request. Characters are UTF-16 code
|
|
53
|
+
units, so an emoji outside the Basic Multilingual Plane counts as two.
|
|
54
|
+
The corresponding settings are `maxDocuments`, `maxLines`, `maxCharacters` and
|
|
55
|
+
`maxTotalCharacters` under `sysml.experimental.validateText`.
|
|
56
|
+
Oversized requests fail with `InvalidParams` before parsing or changing cached
|
|
57
|
+
documents. Disabled requests fail with `MethodNotFound`.
|
|
58
|
+
|
|
59
|
+
Only requested documents are checked. Include an affected existing document
|
|
60
|
+
with its current text to check it too. Results use the server's existing
|
|
61
|
+
diagnostic checks; they do not certify complete SysML conformance.
|
|
62
|
+
Input limits reduce work but do not guarantee a fixed response time.
|
|
63
|
+
|
|
43
64
|
### Install from Marketplace
|
|
44
65
|
|
|
45
66
|
Install via the VS Code extension from the [VS Code Marketplace](https://marketplace.visualstudio.com/items?itemName=JamieD.sysml-v2-support).
|
|
@@ -172,7 +193,7 @@ make bench-history # Stable historical benchmark trends
|
|
|
172
193
|
|
|
173
194
|
## Benchmarks
|
|
174
195
|
|
|
175
|
-
A built-in benchmark suite measures parser, symbol table, LSP provider, memory, throughput,
|
|
196
|
+
A built-in benchmark suite measures parser, symbol table, LSP provider, memory, throughput, folder-load, and `sysml/validateText` performance. Results are written as both JSON and Markdown to `benchmarks/results/`.
|
|
176
197
|
|
|
177
198
|
### Running Benchmarks
|
|
178
199
|
|
|
@@ -195,6 +216,7 @@ npm run bench:history # stable historical trends
|
|
|
195
216
|
| `memory` | Forced-GC retained-heap estimates; use for coarse trends, not precise allocation counts |
|
|
196
217
|
| `throughput` | Syntax-valid lexer/parser throughput, including document-level stale-snapshot recovery |
|
|
197
218
|
| `folderLoad` | Workspace-style file discovery, parse, and symbol build |
|
|
219
|
+
| `validateText` | Main-thread time of a `sysml/validateText` request by workspace, text and request size, and the rebuild it leaves for the next request |
|
|
198
220
|
|
|
199
221
|
### Regression Detection
|
|
200
222
|
|
|
@@ -123,30 +123,30 @@
|
|
|
123
123
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
124
124
|
exports.Message = exports.NotificationType9 = exports.NotificationType8 = exports.NotificationType7 = exports.NotificationType6 = exports.NotificationType5 = exports.NotificationType4 = exports.NotificationType3 = exports.NotificationType2 = exports.NotificationType1 = exports.NotificationType0 = exports.NotificationType = exports.RequestType9 = exports.RequestType8 = exports.RequestType7 = exports.RequestType6 = exports.RequestType5 = exports.RequestType4 = exports.RequestType3 = exports.RequestType2 = exports.RequestType1 = exports.RequestType = exports.RequestType0 = exports.AbstractMessageSignature = exports.ParameterStructures = exports.ResponseError = exports.ErrorCodes = void 0;
|
|
125
125
|
var is = __importStar(require_is());
|
|
126
|
-
var
|
|
127
|
-
(function(
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
})(
|
|
144
|
-
var
|
|
126
|
+
var ErrorCodes3;
|
|
127
|
+
(function(ErrorCodes4) {
|
|
128
|
+
ErrorCodes4.ParseError = -32700;
|
|
129
|
+
ErrorCodes4.InvalidRequest = -32600;
|
|
130
|
+
ErrorCodes4.MethodNotFound = -32601;
|
|
131
|
+
ErrorCodes4.InvalidParams = -32602;
|
|
132
|
+
ErrorCodes4.InternalError = -32603;
|
|
133
|
+
ErrorCodes4.jsonrpcReservedErrorRangeStart = -32099;
|
|
134
|
+
ErrorCodes4.serverErrorStart = -32099;
|
|
135
|
+
ErrorCodes4.MessageWriteError = -32099;
|
|
136
|
+
ErrorCodes4.MessageReadError = -32098;
|
|
137
|
+
ErrorCodes4.PendingResponseRejected = -32097;
|
|
138
|
+
ErrorCodes4.ConnectionInactive = -32096;
|
|
139
|
+
ErrorCodes4.ServerNotInitialized = -32002;
|
|
140
|
+
ErrorCodes4.UnknownErrorCode = -32001;
|
|
141
|
+
ErrorCodes4.jsonrpcReservedErrorRangeEnd = -32e3;
|
|
142
|
+
ErrorCodes4.serverErrorEnd = -32e3;
|
|
143
|
+
})(ErrorCodes3 || (exports.ErrorCodes = ErrorCodes3 = {}));
|
|
144
|
+
var ResponseError3 = class _ResponseError extends Error {
|
|
145
145
|
code;
|
|
146
146
|
data;
|
|
147
147
|
constructor(code, message, data) {
|
|
148
148
|
super(message);
|
|
149
|
-
this.code = is.number(code) ? code :
|
|
149
|
+
this.code = is.number(code) ? code : ErrorCodes3.UnknownErrorCode;
|
|
150
150
|
this.data = data;
|
|
151
151
|
Object.setPrototypeOf(this, _ResponseError.prototype);
|
|
152
152
|
}
|
|
@@ -161,7 +161,7 @@
|
|
|
161
161
|
return result;
|
|
162
162
|
}
|
|
163
163
|
};
|
|
164
|
-
exports.ResponseError =
|
|
164
|
+
exports.ResponseError = ResponseError3;
|
|
165
165
|
var ParameterStructures = class _ParameterStructures {
|
|
166
166
|
kind;
|
|
167
167
|
/**
|
|
@@ -3526,7 +3526,7 @@ ${JSON.stringify(message, null, 4)}`);
|
|
|
3526
3526
|
}
|
|
3527
3527
|
CodeDescription3.is = is;
|
|
3528
3528
|
})(CodeDescription || (CodeDescription = {}));
|
|
3529
|
-
(function(
|
|
3529
|
+
(function(Diagnostic9) {
|
|
3530
3530
|
function create(range, message, severity, code, source, relatedInformation) {
|
|
3531
3531
|
const result = { range, message };
|
|
3532
3532
|
if (Is.defined(severity)) {
|
|
@@ -3543,17 +3543,17 @@ ${JSON.stringify(message, null, 4)}`);
|
|
|
3543
3543
|
}
|
|
3544
3544
|
return result;
|
|
3545
3545
|
}
|
|
3546
|
-
|
|
3546
|
+
Diagnostic9.create = create;
|
|
3547
3547
|
function is(value) {
|
|
3548
3548
|
var _a;
|
|
3549
3549
|
const candidate = value;
|
|
3550
3550
|
return Is.defined(candidate) && Range.is(candidate.range) && (Is.string(candidate.message) || MarkupContent.is(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));
|
|
3551
3551
|
}
|
|
3552
|
-
|
|
3552
|
+
Diagnostic9.is = is;
|
|
3553
3553
|
function is3_17(value) {
|
|
3554
3554
|
return Is.string(value.message);
|
|
3555
3555
|
}
|
|
3556
|
-
|
|
3556
|
+
Diagnostic9.is3_17 = is3_17;
|
|
3557
3557
|
function getMessageString(diagnostic) {
|
|
3558
3558
|
if (Is.string(diagnostic.message)) {
|
|
3559
3559
|
return diagnostic.message;
|
|
@@ -3563,7 +3563,7 @@ ${JSON.stringify(message, null, 4)}`);
|
|
|
3563
3563
|
throw new Error(`Unknown message type ${typeof diagnostic.message}`);
|
|
3564
3564
|
}
|
|
3565
3565
|
}
|
|
3566
|
-
|
|
3566
|
+
Diagnostic9.getMessageString = getMessageString;
|
|
3567
3567
|
})(Diagnostic || (Diagnostic = {}));
|
|
3568
3568
|
(function(Command3) {
|
|
3569
3569
|
function create(title, command, ...args) {
|
|
@@ -9290,28 +9290,28 @@ ${JSON.stringify(message, null, 4)}`);
|
|
|
9290
9290
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9291
9291
|
exports.Message = exports.NotificationType9 = exports.NotificationType8 = exports.NotificationType7 = exports.NotificationType6 = exports.NotificationType5 = exports.NotificationType4 = exports.NotificationType3 = exports.NotificationType2 = exports.NotificationType1 = exports.NotificationType0 = exports.NotificationType = exports.RequestType9 = exports.RequestType8 = exports.RequestType7 = exports.RequestType6 = exports.RequestType5 = exports.RequestType4 = exports.RequestType3 = exports.RequestType2 = exports.RequestType1 = exports.RequestType = exports.RequestType0 = exports.AbstractMessageSignature = exports.ParameterStructures = exports.ResponseError = exports.ErrorCodes = void 0;
|
|
9292
9292
|
var is = require_is4();
|
|
9293
|
-
var
|
|
9294
|
-
(function(
|
|
9295
|
-
|
|
9296
|
-
|
|
9297
|
-
|
|
9298
|
-
|
|
9299
|
-
|
|
9300
|
-
|
|
9301
|
-
|
|
9302
|
-
|
|
9303
|
-
|
|
9304
|
-
|
|
9305
|
-
|
|
9306
|
-
|
|
9307
|
-
|
|
9308
|
-
|
|
9309
|
-
|
|
9310
|
-
})(
|
|
9311
|
-
var
|
|
9293
|
+
var ErrorCodes3;
|
|
9294
|
+
(function(ErrorCodes4) {
|
|
9295
|
+
ErrorCodes4.ParseError = -32700;
|
|
9296
|
+
ErrorCodes4.InvalidRequest = -32600;
|
|
9297
|
+
ErrorCodes4.MethodNotFound = -32601;
|
|
9298
|
+
ErrorCodes4.InvalidParams = -32602;
|
|
9299
|
+
ErrorCodes4.InternalError = -32603;
|
|
9300
|
+
ErrorCodes4.jsonrpcReservedErrorRangeStart = -32099;
|
|
9301
|
+
ErrorCodes4.serverErrorStart = -32099;
|
|
9302
|
+
ErrorCodes4.MessageWriteError = -32099;
|
|
9303
|
+
ErrorCodes4.MessageReadError = -32098;
|
|
9304
|
+
ErrorCodes4.PendingResponseRejected = -32097;
|
|
9305
|
+
ErrorCodes4.ConnectionInactive = -32096;
|
|
9306
|
+
ErrorCodes4.ServerNotInitialized = -32002;
|
|
9307
|
+
ErrorCodes4.UnknownErrorCode = -32001;
|
|
9308
|
+
ErrorCodes4.jsonrpcReservedErrorRangeEnd = -32e3;
|
|
9309
|
+
ErrorCodes4.serverErrorEnd = -32e3;
|
|
9310
|
+
})(ErrorCodes3 || (exports.ErrorCodes = ErrorCodes3 = {}));
|
|
9311
|
+
var ResponseError3 = class _ResponseError extends Error {
|
|
9312
9312
|
constructor(code, message, data) {
|
|
9313
9313
|
super(message);
|
|
9314
|
-
this.code = is.number(code) ? code :
|
|
9314
|
+
this.code = is.number(code) ? code : ErrorCodes3.UnknownErrorCode;
|
|
9315
9315
|
this.data = data;
|
|
9316
9316
|
Object.setPrototypeOf(this, _ResponseError.prototype);
|
|
9317
9317
|
}
|
|
@@ -9326,7 +9326,7 @@ ${JSON.stringify(message, null, 4)}`);
|
|
|
9326
9326
|
return result;
|
|
9327
9327
|
}
|
|
9328
9328
|
};
|
|
9329
|
-
exports.ResponseError =
|
|
9329
|
+
exports.ResponseError = ResponseError3;
|
|
9330
9330
|
var ParameterStructures = class _ParameterStructures {
|
|
9331
9331
|
constructor(kind) {
|
|
9332
9332
|
this.kind = kind;
|
|
@@ -12599,7 +12599,7 @@ ${JSON.stringify(message, null, 4)}`);
|
|
|
12599
12599
|
}
|
|
12600
12600
|
CodeDescription3.is = is;
|
|
12601
12601
|
})(CodeDescription2 || (CodeDescription2 = {}));
|
|
12602
|
-
(function(
|
|
12602
|
+
(function(Diagnostic9) {
|
|
12603
12603
|
function create(range, message, severity, code, source, relatedInformation) {
|
|
12604
12604
|
let result = { range, message };
|
|
12605
12605
|
if (Is2.defined(severity)) {
|
|
@@ -12616,13 +12616,13 @@ ${JSON.stringify(message, null, 4)}`);
|
|
|
12616
12616
|
}
|
|
12617
12617
|
return result;
|
|
12618
12618
|
}
|
|
12619
|
-
|
|
12619
|
+
Diagnostic9.create = create;
|
|
12620
12620
|
function is(value) {
|
|
12621
12621
|
var _a;
|
|
12622
12622
|
let candidate = value;
|
|
12623
12623
|
return Is2.defined(candidate) && Range2.is(candidate.range) && Is2.string(candidate.message) && (Is2.number(candidate.severity) || Is2.undefined(candidate.severity)) && (Is2.integer(candidate.code) || Is2.string(candidate.code) || Is2.undefined(candidate.code)) && (Is2.undefined(candidate.codeDescription) || Is2.string((_a = candidate.codeDescription) === null || _a === void 0 ? void 0 : _a.href)) && (Is2.string(candidate.source) || Is2.undefined(candidate.source)) && (Is2.undefined(candidate.relatedInformation) || Is2.typedArray(candidate.relatedInformation, DiagnosticRelatedInformation2.is));
|
|
12624
12624
|
}
|
|
12625
|
-
|
|
12625
|
+
Diagnostic9.is = is;
|
|
12626
12626
|
})(Diagnostic2 || (Diagnostic2 = {}));
|
|
12627
12627
|
(function(Command3) {
|
|
12628
12628
|
function create(title, command, ...args) {
|
|
@@ -17437,7 +17437,7 @@ ${JSON.stringify(message, null, 4)}`);
|
|
|
17437
17437
|
});
|
|
17438
17438
|
|
|
17439
17439
|
// server/src/server.ts
|
|
17440
|
-
var
|
|
17440
|
+
var import_node14 = __toESM(require_main3());
|
|
17441
17441
|
|
|
17442
17442
|
// server/src/platform/shims/fs.ts
|
|
17443
17443
|
function readFileSync(_path, _enc) {
|
|
@@ -133028,6 +133028,13 @@ ${JSON.stringify(message, null, 4)}`);
|
|
|
133028
133028
|
* indexed yet" apart from "genuinely doesn't exist".
|
|
133029
133029
|
*/
|
|
133030
133030
|
workspaceScanComplete = true;
|
|
133031
|
+
/**
|
|
133032
|
+
* Last version given to a stand-in text by `withTexts`. Caches keyed by
|
|
133033
|
+
* version assume one text per uri and version, so each stand-in gets a
|
|
133034
|
+
* version outside the LSP integer range (LSP 3.17, base types).
|
|
133035
|
+
* These internal positive versions are never sent to the client.
|
|
133036
|
+
*/
|
|
133037
|
+
temporaryVersion = 2 ** 31 - 1;
|
|
133031
133038
|
/**
|
|
133032
133039
|
* Parse a document and cache the result.
|
|
133033
133040
|
* Returns the cached result if the content hasn't changed.
|
|
@@ -133231,6 +133238,35 @@ ${JSON.stringify(message, null, 4)}`);
|
|
|
133231
133238
|
this.wsSymbolTable.removeUri(uri);
|
|
133232
133239
|
this.wsBuiltVersions.delete(uri);
|
|
133233
133240
|
}
|
|
133241
|
+
/**
|
|
133242
|
+
* Runs `fn` with each text standing in for the document at its uri (or
|
|
133243
|
+
* added as a new document), all at once, then restores the previous
|
|
133244
|
+
* state. `fn` must be synchronous: no other request can run in between,
|
|
133245
|
+
* so no other request ever sees the temporary texts. Every text is
|
|
133246
|
+
* parsed before anything changes. The stand-ins get versions no real
|
|
133247
|
+
* document has, so caches keyed by version never confuse them with the
|
|
133248
|
+
* real documents.
|
|
133249
|
+
*/
|
|
133250
|
+
withTexts(documents2, fn) {
|
|
133251
|
+
if (!Number.isSafeInteger(this.temporaryVersion + documents2.length)) {
|
|
133252
|
+
throw new RangeError("Temporary document version space exhausted.");
|
|
133253
|
+
}
|
|
133254
|
+
const parsed = documents2.map(({ uri, text }) => ({ uri, text, result: parseDocument(text) }));
|
|
133255
|
+
const previous = new Map(parsed.map(({ uri }) => [uri, this.cache.get(uri)]));
|
|
133256
|
+
for (const { uri, text, result } of parsed) {
|
|
133257
|
+
this.cache.set(uri, { version: ++this.temporaryVersion, text, result, needsParse: false });
|
|
133258
|
+
}
|
|
133259
|
+
try {
|
|
133260
|
+
return fn();
|
|
133261
|
+
} finally {
|
|
133262
|
+
for (const [uri, entry] of previous) {
|
|
133263
|
+
if (entry) this.cache.set(uri, entry);
|
|
133264
|
+
else this.cache.delete(uri);
|
|
133265
|
+
this.wsSymbolTable.removeUri(uri);
|
|
133266
|
+
this.wsBuiltVersions.delete(uri);
|
|
133267
|
+
}
|
|
133268
|
+
}
|
|
133269
|
+
}
|
|
133234
133270
|
/**
|
|
133235
133271
|
* Get all cached URIs.
|
|
133236
133272
|
*/
|
|
@@ -142068,6 +142104,115 @@ ${info.documentation}`);
|
|
|
142068
142104
|
}
|
|
142069
142105
|
};
|
|
142070
142106
|
|
|
142107
|
+
// server/src/providers/textValidationProvider.ts
|
|
142108
|
+
var import_node13 = __toESM(require_main3());
|
|
142109
|
+
var DEFAULT_TEXT_VALIDATION_SETTINGS = {
|
|
142110
|
+
enabled: false,
|
|
142111
|
+
maxDocuments: 5,
|
|
142112
|
+
maxLines: 200,
|
|
142113
|
+
maxCharacters: 8192,
|
|
142114
|
+
maxTotalCharacters: 16384
|
|
142115
|
+
};
|
|
142116
|
+
function readTextValidationSettings(section) {
|
|
142117
|
+
const raw = typeof section === "object" && section !== null ? section : {};
|
|
142118
|
+
const limit = (value, fallback) => Number.isSafeInteger(value) && value > 0 ? value : fallback;
|
|
142119
|
+
return {
|
|
142120
|
+
enabled: raw.enabled === true,
|
|
142121
|
+
maxDocuments: limit(raw.maxDocuments, DEFAULT_TEXT_VALIDATION_SETTINGS.maxDocuments),
|
|
142122
|
+
maxLines: limit(raw.maxLines, DEFAULT_TEXT_VALIDATION_SETTINGS.maxLines),
|
|
142123
|
+
maxCharacters: limit(raw.maxCharacters, DEFAULT_TEXT_VALIDATION_SETTINGS.maxCharacters),
|
|
142124
|
+
maxTotalCharacters: limit(raw.maxTotalCharacters, DEFAULT_TEXT_VALIDATION_SETTINGS.maxTotalCharacters)
|
|
142125
|
+
};
|
|
142126
|
+
}
|
|
142127
|
+
var TextValidationProvider = class {
|
|
142128
|
+
/**
|
|
142129
|
+
* `isReported` filters diagnostics as the server does before
|
|
142130
|
+
* publishing them (`sysml.validation.disabledCodes`), so a text gets
|
|
142131
|
+
* exactly what it would get as an open document.
|
|
142132
|
+
*/
|
|
142133
|
+
constructor(documentManager2, semanticValidator2, isReported2 = () => true) {
|
|
142134
|
+
this.documentManager = documentManager2;
|
|
142135
|
+
this.semanticValidator = semanticValidator2;
|
|
142136
|
+
this.isReported = isReported2;
|
|
142137
|
+
}
|
|
142138
|
+
documentManager;
|
|
142139
|
+
semanticValidator;
|
|
142140
|
+
isReported;
|
|
142141
|
+
settings = { ...DEFAULT_TEXT_VALIDATION_SETTINGS };
|
|
142142
|
+
/** Applies the client's settings to the requests that follow. */
|
|
142143
|
+
configure(settings) {
|
|
142144
|
+
this.settings = { ...settings };
|
|
142145
|
+
}
|
|
142146
|
+
/**
|
|
142147
|
+
* The diagnostics each text would get as an open document, with all
|
|
142148
|
+
* texts in place at the same time. Answers `MethodNotFound` while
|
|
142149
|
+
* disabled, and `InvalidParams` for malformed parameters or parameters
|
|
142150
|
+
* over a limit.
|
|
142151
|
+
*/
|
|
142152
|
+
validate(params) {
|
|
142153
|
+
if (!this.settings.enabled) {
|
|
142154
|
+
throw new import_node13.ResponseError(
|
|
142155
|
+
import_node13.ErrorCodes.MethodNotFound,
|
|
142156
|
+
"sysml/validateText is experimental and disabled: set sysml.experimental.validateText.enabled to true."
|
|
142157
|
+
);
|
|
142158
|
+
}
|
|
142159
|
+
const documents2 = this.checkDocuments(params?.documents);
|
|
142160
|
+
const known = documents2.map((document) => ({ uri: this.knownSpelling(document.uri), text: document.text }));
|
|
142161
|
+
const diagnostics = this.documentManager.withTexts(known, () => known.map(({ uri }) => this.diagnose(uri)));
|
|
142162
|
+
return { documents: documents2.map((document, index2) => ({ uri: document.uri, diagnostics: diagnostics[index2] })) };
|
|
142163
|
+
}
|
|
142164
|
+
/** `documents` checked: a non-empty array of `{ uri, text }` within the limits, each naming a different document. */
|
|
142165
|
+
checkDocuments(documents2) {
|
|
142166
|
+
if (!Array.isArray(documents2) || documents2.length === 0) invalid('"documents" must be a non-empty array of { uri, text }.');
|
|
142167
|
+
const { maxDocuments, maxLines, maxCharacters, maxTotalCharacters } = this.settings;
|
|
142168
|
+
if (documents2.length > maxDocuments) {
|
|
142169
|
+
invalid(`${documents2.length} documents, more than the ${maxDocuments} allowed (sysml.experimental.validateText.maxDocuments).`);
|
|
142170
|
+
}
|
|
142171
|
+
const checked = documents2;
|
|
142172
|
+
let totalCharacters = 0;
|
|
142173
|
+
checked.forEach((document, index2) => {
|
|
142174
|
+
if (typeof document?.text !== "string") invalid(`documents[${index2}] needs "text", the SysML text to validate.`);
|
|
142175
|
+
if (document.text.length > maxCharacters) {
|
|
142176
|
+
invalid(`documents[${index2}] has ${document.text.length} characters, more than the ${maxCharacters} allowed (sysml.experimental.validateText.maxCharacters).`);
|
|
142177
|
+
}
|
|
142178
|
+
totalCharacters += document.text.length;
|
|
142179
|
+
if (totalCharacters > maxTotalCharacters) {
|
|
142180
|
+
invalid(`${totalCharacters} total characters, more than the ${maxTotalCharacters} allowed (sysml.experimental.validateText.maxTotalCharacters).`);
|
|
142181
|
+
}
|
|
142182
|
+
const lines = lineCount(document.text);
|
|
142183
|
+
if (lines > maxLines) {
|
|
142184
|
+
invalid(`documents[${index2}] has ${lines} lines, more than the ${maxLines} allowed (sysml.experimental.validateText.maxLines).`);
|
|
142185
|
+
}
|
|
142186
|
+
if (!isUri(document.uri)) invalid(`documents[${index2}] needs "uri", the document the text is the content of.`);
|
|
142187
|
+
const earlier = checked.findIndex((other) => isSameDocumentUri(other.uri, document.uri));
|
|
142188
|
+
if (earlier !== index2) invalid(`documents[${earlier}] and documents[${index2}] name the same document.`);
|
|
142189
|
+
});
|
|
142190
|
+
return checked;
|
|
142191
|
+
}
|
|
142192
|
+
/** The syntax, keyword and semantic diagnostics of the document at `uri`, as published for an open document. */
|
|
142193
|
+
diagnose(uri) {
|
|
142194
|
+
const diagnostics = new DiagnosticsProvider(this.documentManager).getDiagnostics(uri);
|
|
142195
|
+
const parseResult = this.documentManager.get(uri);
|
|
142196
|
+
if (parseResult) diagnostics.push(...validateKeywords(parseResult));
|
|
142197
|
+
diagnostics.push(...this.semanticValidator.validate(uri));
|
|
142198
|
+
return diagnostics.filter(this.isReported);
|
|
142199
|
+
}
|
|
142200
|
+
/** The spelling under which the server knows the document `uri` names, else `uri` itself (see `isSameDocumentUri`). */
|
|
142201
|
+
knownSpelling(uri) {
|
|
142202
|
+
return this.documentManager.getUris().find((known) => isSameDocumentUri(known, uri)) ?? uri;
|
|
142203
|
+
}
|
|
142204
|
+
};
|
|
142205
|
+
function lineCount(text) {
|
|
142206
|
+
const breaks = text.match(/\r\n|\r|\n/g)?.length ?? 0;
|
|
142207
|
+
return text === "" || /[\r\n]$/.test(text) ? breaks : breaks + 1;
|
|
142208
|
+
}
|
|
142209
|
+
function isUri(value) {
|
|
142210
|
+
return typeof value === "string" && value.trim() !== "";
|
|
142211
|
+
}
|
|
142212
|
+
function invalid(message) {
|
|
142213
|
+
throw new import_node13.ResponseError(import_node13.ErrorCodes.InvalidParams, `sysml/validateText: ${message}`);
|
|
142214
|
+
}
|
|
142215
|
+
|
|
142071
142216
|
// server/src/platform/shims/fs-promises.ts
|
|
142072
142217
|
async function readFile(_path, _enc) {
|
|
142073
142218
|
throw new Error("fs/promises.readFile is not available in the browser");
|
|
@@ -142148,7 +142293,7 @@ ${info.documentation}`);
|
|
|
142148
142293
|
return void 0;
|
|
142149
142294
|
}
|
|
142150
142295
|
var connection = createServerConnection();
|
|
142151
|
-
var documents = new
|
|
142296
|
+
var documents = new import_node14.TextDocuments(TextDocument2);
|
|
142152
142297
|
var serverStartTime = Date.now();
|
|
142153
142298
|
var documentManager = new DocumentManager();
|
|
142154
142299
|
var modelProvider = new SysMLModelProvider(documentManager);
|
|
@@ -142165,6 +142310,7 @@ ${info.documentation}`);
|
|
|
142165
142310
|
var codeActionProvider = new CodeActionProvider(documentManager);
|
|
142166
142311
|
var formattingProvider = new FormattingProvider(documents);
|
|
142167
142312
|
var semanticValidator = new SemanticValidator(documentManager);
|
|
142313
|
+
var textValidationProvider = new TextValidationProvider(documentManager, semanticValidator, isReported);
|
|
142168
142314
|
hoverProvider.setSemanticValidator(semanticValidator);
|
|
142169
142315
|
var hasConfigurationCapability = false;
|
|
142170
142316
|
var hasWorkspaceFolderCapability = false;
|
|
@@ -142176,11 +142322,11 @@ ${info.documentation}`);
|
|
|
142176
142322
|
var isWorkspaceFile = false;
|
|
142177
142323
|
var preloadOnOpen = "workspaceOnly";
|
|
142178
142324
|
var disabledDiagnosticCodes = /* @__PURE__ */ new Set();
|
|
142325
|
+
function isReported(diagnostic) {
|
|
142326
|
+
return diagnostic.code === void 0 || !disabledDiagnosticCodes.has(String(diagnostic.code));
|
|
142327
|
+
}
|
|
142179
142328
|
function publishDiagnostics(uri, diagnostics) {
|
|
142180
|
-
connection.sendDiagnostics({
|
|
142181
|
-
uri,
|
|
142182
|
-
diagnostics: diagnostics.filter((diagnostic) => diagnostic.code === void 0 || !disabledDiagnosticCodes.has(String(diagnostic.code)))
|
|
142183
|
-
});
|
|
142329
|
+
connection.sendDiagnostics({ uri, diagnostics: diagnostics.filter(isReported) });
|
|
142184
142330
|
}
|
|
142185
142331
|
var skipDirs = new Set(DEFAULT_SKIP_DIRS);
|
|
142186
142332
|
var serverReady = false;
|
|
@@ -142313,7 +142459,7 @@ ${info.documentation}`);
|
|
|
142313
142459
|
};
|
|
142314
142460
|
const result = {
|
|
142315
142461
|
capabilities: {
|
|
142316
|
-
textDocumentSync:
|
|
142462
|
+
textDocumentSync: import_node14.TextDocumentSyncKind.Incremental,
|
|
142317
142463
|
// Completion
|
|
142318
142464
|
completionProvider: {
|
|
142319
142465
|
resolveProvider: true,
|
|
@@ -142341,7 +142487,7 @@ ${info.documentation}`);
|
|
|
142341
142487
|
// Code actions (quick fixes)
|
|
142342
142488
|
codeActionProvider: {
|
|
142343
142489
|
codeActionKinds: [
|
|
142344
|
-
|
|
142490
|
+
import_node14.CodeActionKind.QuickFix
|
|
142345
142491
|
]
|
|
142346
142492
|
},
|
|
142347
142493
|
// Document formatting
|
|
@@ -142362,7 +142508,7 @@ ${info.documentation}`);
|
|
|
142362
142508
|
connection.onInitialized(async () => {
|
|
142363
142509
|
if (hasConfigurationCapability) {
|
|
142364
142510
|
connection.client.register(
|
|
142365
|
-
|
|
142511
|
+
import_node14.DidChangeConfigurationNotification.type,
|
|
142366
142512
|
void 0
|
|
142367
142513
|
);
|
|
142368
142514
|
}
|
|
@@ -142423,6 +142569,8 @@ ${info.documentation}`);
|
|
|
142423
142569
|
const validation = await connection.workspace.getConfiguration("sysml.validation");
|
|
142424
142570
|
const codes = validation?.disabledCodes;
|
|
142425
142571
|
disabledDiagnosticCodes = new Set(Array.isArray(codes) ? codes.filter((code) => typeof code === "string") : []);
|
|
142572
|
+
const experimental = await connection.workspace.getConfiguration("sysml.experimental");
|
|
142573
|
+
textValidationProvider.configure(readTextValidationSettings(experimental?.validateText));
|
|
142426
142574
|
}
|
|
142427
142575
|
function applySettings(config) {
|
|
142428
142576
|
if (!config) return;
|
|
@@ -142776,6 +142924,10 @@ ${info.documentation}`);
|
|
|
142776
142924
|
await initialization;
|
|
142777
142925
|
return elementLookupProvider.elementLookup(params);
|
|
142778
142926
|
});
|
|
142927
|
+
connection.onRequest("sysml/validateText", async (params) => {
|
|
142928
|
+
await initialization;
|
|
142929
|
+
return textValidationProvider.validate(params);
|
|
142930
|
+
});
|
|
142779
142931
|
connection.onRequest("sysml/serverStats", () => {
|
|
142780
142932
|
const mem = typeof process !== "undefined" && typeof process.memoryUsage === "function" ? process.memoryUsage() : { heapUsed: 0, heapTotal: 0, rss: 0, external: 0 };
|
|
142781
142933
|
const toMB = (bytes) => Math.round(bytes / 1024 / 1024);
|
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
|
*/
|
|
@@ -131036,6 +131072,115 @@ var SemanticValidator = class _SemanticValidator {
|
|
|
131036
131072
|
}
|
|
131037
131073
|
};
|
|
131038
131074
|
|
|
131075
|
+
// server/src/providers/textValidationProvider.ts
|
|
131076
|
+
var import_node14 = __toESM(require_node3());
|
|
131077
|
+
var DEFAULT_TEXT_VALIDATION_SETTINGS = {
|
|
131078
|
+
enabled: false,
|
|
131079
|
+
maxDocuments: 5,
|
|
131080
|
+
maxLines: 200,
|
|
131081
|
+
maxCharacters: 8192,
|
|
131082
|
+
maxTotalCharacters: 16384
|
|
131083
|
+
};
|
|
131084
|
+
function readTextValidationSettings(section) {
|
|
131085
|
+
const raw = typeof section === "object" && section !== null ? section : {};
|
|
131086
|
+
const limit = (value, fallback) => Number.isSafeInteger(value) && value > 0 ? value : fallback;
|
|
131087
|
+
return {
|
|
131088
|
+
enabled: raw.enabled === true,
|
|
131089
|
+
maxDocuments: limit(raw.maxDocuments, DEFAULT_TEXT_VALIDATION_SETTINGS.maxDocuments),
|
|
131090
|
+
maxLines: limit(raw.maxLines, DEFAULT_TEXT_VALIDATION_SETTINGS.maxLines),
|
|
131091
|
+
maxCharacters: limit(raw.maxCharacters, DEFAULT_TEXT_VALIDATION_SETTINGS.maxCharacters),
|
|
131092
|
+
maxTotalCharacters: limit(raw.maxTotalCharacters, DEFAULT_TEXT_VALIDATION_SETTINGS.maxTotalCharacters)
|
|
131093
|
+
};
|
|
131094
|
+
}
|
|
131095
|
+
var TextValidationProvider = class {
|
|
131096
|
+
/**
|
|
131097
|
+
* `isReported` filters diagnostics as the server does before
|
|
131098
|
+
* publishing them (`sysml.validation.disabledCodes`), so a text gets
|
|
131099
|
+
* exactly what it would get as an open document.
|
|
131100
|
+
*/
|
|
131101
|
+
constructor(documentManager2, semanticValidator2, isReported2 = () => true) {
|
|
131102
|
+
this.documentManager = documentManager2;
|
|
131103
|
+
this.semanticValidator = semanticValidator2;
|
|
131104
|
+
this.isReported = isReported2;
|
|
131105
|
+
}
|
|
131106
|
+
documentManager;
|
|
131107
|
+
semanticValidator;
|
|
131108
|
+
isReported;
|
|
131109
|
+
settings = { ...DEFAULT_TEXT_VALIDATION_SETTINGS };
|
|
131110
|
+
/** Applies the client's settings to the requests that follow. */
|
|
131111
|
+
configure(settings) {
|
|
131112
|
+
this.settings = { ...settings };
|
|
131113
|
+
}
|
|
131114
|
+
/**
|
|
131115
|
+
* The diagnostics each text would get as an open document, with all
|
|
131116
|
+
* texts in place at the same time. Answers `MethodNotFound` while
|
|
131117
|
+
* disabled, and `InvalidParams` for malformed parameters or parameters
|
|
131118
|
+
* over a limit.
|
|
131119
|
+
*/
|
|
131120
|
+
validate(params) {
|
|
131121
|
+
if (!this.settings.enabled) {
|
|
131122
|
+
throw new import_node14.ResponseError(
|
|
131123
|
+
import_node14.ErrorCodes.MethodNotFound,
|
|
131124
|
+
"sysml/validateText is experimental and disabled: set sysml.experimental.validateText.enabled to true."
|
|
131125
|
+
);
|
|
131126
|
+
}
|
|
131127
|
+
const documents2 = this.checkDocuments(params?.documents);
|
|
131128
|
+
const known = documents2.map((document) => ({ uri: this.knownSpelling(document.uri), text: document.text }));
|
|
131129
|
+
const diagnostics = this.documentManager.withTexts(known, () => known.map(({ uri }) => this.diagnose(uri)));
|
|
131130
|
+
return { documents: documents2.map((document, index2) => ({ uri: document.uri, diagnostics: diagnostics[index2] })) };
|
|
131131
|
+
}
|
|
131132
|
+
/** `documents` checked: a non-empty array of `{ uri, text }` within the limits, each naming a different document. */
|
|
131133
|
+
checkDocuments(documents2) {
|
|
131134
|
+
if (!Array.isArray(documents2) || documents2.length === 0) invalid('"documents" must be a non-empty array of { uri, text }.');
|
|
131135
|
+
const { maxDocuments, maxLines, maxCharacters, maxTotalCharacters } = this.settings;
|
|
131136
|
+
if (documents2.length > maxDocuments) {
|
|
131137
|
+
invalid(`${documents2.length} documents, more than the ${maxDocuments} allowed (sysml.experimental.validateText.maxDocuments).`);
|
|
131138
|
+
}
|
|
131139
|
+
const checked = documents2;
|
|
131140
|
+
let totalCharacters = 0;
|
|
131141
|
+
checked.forEach((document, index2) => {
|
|
131142
|
+
if (typeof document?.text !== "string") invalid(`documents[${index2}] needs "text", the SysML text to validate.`);
|
|
131143
|
+
if (document.text.length > maxCharacters) {
|
|
131144
|
+
invalid(`documents[${index2}] has ${document.text.length} characters, more than the ${maxCharacters} allowed (sysml.experimental.validateText.maxCharacters).`);
|
|
131145
|
+
}
|
|
131146
|
+
totalCharacters += document.text.length;
|
|
131147
|
+
if (totalCharacters > maxTotalCharacters) {
|
|
131148
|
+
invalid(`${totalCharacters} total characters, more than the ${maxTotalCharacters} allowed (sysml.experimental.validateText.maxTotalCharacters).`);
|
|
131149
|
+
}
|
|
131150
|
+
const lines = lineCount(document.text);
|
|
131151
|
+
if (lines > maxLines) {
|
|
131152
|
+
invalid(`documents[${index2}] has ${lines} lines, more than the ${maxLines} allowed (sysml.experimental.validateText.maxLines).`);
|
|
131153
|
+
}
|
|
131154
|
+
if (!isUri(document.uri)) invalid(`documents[${index2}] needs "uri", the document the text is the content of.`);
|
|
131155
|
+
const earlier = checked.findIndex((other) => isSameDocumentUri(other.uri, document.uri));
|
|
131156
|
+
if (earlier !== index2) invalid(`documents[${earlier}] and documents[${index2}] name the same document.`);
|
|
131157
|
+
});
|
|
131158
|
+
return checked;
|
|
131159
|
+
}
|
|
131160
|
+
/** The syntax, keyword and semantic diagnostics of the document at `uri`, as published for an open document. */
|
|
131161
|
+
diagnose(uri) {
|
|
131162
|
+
const diagnostics = new DiagnosticsProvider(this.documentManager).getDiagnostics(uri);
|
|
131163
|
+
const parseResult = this.documentManager.get(uri);
|
|
131164
|
+
if (parseResult) diagnostics.push(...validateKeywords(parseResult));
|
|
131165
|
+
diagnostics.push(...this.semanticValidator.validate(uri));
|
|
131166
|
+
return diagnostics.filter(this.isReported);
|
|
131167
|
+
}
|
|
131168
|
+
/** The spelling under which the server knows the document `uri` names, else `uri` itself (see `isSameDocumentUri`). */
|
|
131169
|
+
knownSpelling(uri) {
|
|
131170
|
+
return this.documentManager.getUris().find((known) => isSameDocumentUri(known, uri)) ?? uri;
|
|
131171
|
+
}
|
|
131172
|
+
};
|
|
131173
|
+
function lineCount(text) {
|
|
131174
|
+
const breaks = text.match(/\r\n|\r|\n/g)?.length ?? 0;
|
|
131175
|
+
return text === "" || /[\r\n]$/.test(text) ? breaks : breaks + 1;
|
|
131176
|
+
}
|
|
131177
|
+
function isUri(value) {
|
|
131178
|
+
return typeof value === "string" && value.trim() !== "";
|
|
131179
|
+
}
|
|
131180
|
+
function invalid(message) {
|
|
131181
|
+
throw new import_node14.ResponseError(import_node14.ErrorCodes.InvalidParams, `sysml/validateText: ${message}`);
|
|
131182
|
+
}
|
|
131183
|
+
|
|
131039
131184
|
// server/src/utils/fileDiscovery.ts
|
|
131040
131185
|
var fsp = __toESM(require("node:fs/promises"));
|
|
131041
131186
|
var path = __toESM(require("node:path"));
|
|
@@ -131110,7 +131255,7 @@ function toFsPath(uri) {
|
|
|
131110
131255
|
return void 0;
|
|
131111
131256
|
}
|
|
131112
131257
|
var connection = createServerConnection();
|
|
131113
|
-
var documents = new
|
|
131258
|
+
var documents = new import_node15.TextDocuments(TextDocument);
|
|
131114
131259
|
var serverStartTime = Date.now();
|
|
131115
131260
|
var documentManager = new DocumentManager();
|
|
131116
131261
|
var modelProvider = new SysMLModelProvider(documentManager);
|
|
@@ -131127,6 +131272,7 @@ var renameProvider = new RenameProvider(documentManager);
|
|
|
131127
131272
|
var codeActionProvider = new CodeActionProvider(documentManager);
|
|
131128
131273
|
var formattingProvider = new FormattingProvider(documents);
|
|
131129
131274
|
var semanticValidator = new SemanticValidator(documentManager);
|
|
131275
|
+
var textValidationProvider = new TextValidationProvider(documentManager, semanticValidator, isReported);
|
|
131130
131276
|
hoverProvider.setSemanticValidator(semanticValidator);
|
|
131131
131277
|
var hasConfigurationCapability = false;
|
|
131132
131278
|
var hasWorkspaceFolderCapability = false;
|
|
@@ -131138,11 +131284,11 @@ function rootsOf(folderUris) {
|
|
|
131138
131284
|
var isWorkspaceFile = false;
|
|
131139
131285
|
var preloadOnOpen = "workspaceOnly";
|
|
131140
131286
|
var disabledDiagnosticCodes = /* @__PURE__ */ new Set();
|
|
131287
|
+
function isReported(diagnostic) {
|
|
131288
|
+
return diagnostic.code === void 0 || !disabledDiagnosticCodes.has(String(diagnostic.code));
|
|
131289
|
+
}
|
|
131141
131290
|
function publishDiagnostics(uri, diagnostics) {
|
|
131142
|
-
connection.sendDiagnostics({
|
|
131143
|
-
uri,
|
|
131144
|
-
diagnostics: diagnostics.filter((diagnostic) => diagnostic.code === void 0 || !disabledDiagnosticCodes.has(String(diagnostic.code)))
|
|
131145
|
-
});
|
|
131291
|
+
connection.sendDiagnostics({ uri, diagnostics: diagnostics.filter(isReported) });
|
|
131146
131292
|
}
|
|
131147
131293
|
var skipDirs = new Set(DEFAULT_SKIP_DIRS);
|
|
131148
131294
|
var serverReady = false;
|
|
@@ -131275,7 +131421,7 @@ connection.onInitialize((params) => {
|
|
|
131275
131421
|
};
|
|
131276
131422
|
const result = {
|
|
131277
131423
|
capabilities: {
|
|
131278
|
-
textDocumentSync:
|
|
131424
|
+
textDocumentSync: import_node15.TextDocumentSyncKind.Incremental,
|
|
131279
131425
|
// Completion
|
|
131280
131426
|
completionProvider: {
|
|
131281
131427
|
resolveProvider: true,
|
|
@@ -131303,7 +131449,7 @@ connection.onInitialize((params) => {
|
|
|
131303
131449
|
// Code actions (quick fixes)
|
|
131304
131450
|
codeActionProvider: {
|
|
131305
131451
|
codeActionKinds: [
|
|
131306
|
-
|
|
131452
|
+
import_node15.CodeActionKind.QuickFix
|
|
131307
131453
|
]
|
|
131308
131454
|
},
|
|
131309
131455
|
// Document formatting
|
|
@@ -131324,7 +131470,7 @@ connection.onInitialize((params) => {
|
|
|
131324
131470
|
connection.onInitialized(async () => {
|
|
131325
131471
|
if (hasConfigurationCapability) {
|
|
131326
131472
|
connection.client.register(
|
|
131327
|
-
|
|
131473
|
+
import_node15.DidChangeConfigurationNotification.type,
|
|
131328
131474
|
void 0
|
|
131329
131475
|
);
|
|
131330
131476
|
}
|
|
@@ -131385,6 +131531,8 @@ async function pullSettings() {
|
|
|
131385
131531
|
const validation = await connection.workspace.getConfiguration("sysml.validation");
|
|
131386
131532
|
const codes = validation?.disabledCodes;
|
|
131387
131533
|
disabledDiagnosticCodes = new Set(Array.isArray(codes) ? codes.filter((code) => typeof code === "string") : []);
|
|
131534
|
+
const experimental = await connection.workspace.getConfiguration("sysml.experimental");
|
|
131535
|
+
textValidationProvider.configure(readTextValidationSettings(experimental?.validateText));
|
|
131388
131536
|
}
|
|
131389
131537
|
function applySettings(config) {
|
|
131390
131538
|
if (!config) return;
|
|
@@ -131738,6 +131886,10 @@ connection.onRequest("sysml/elementLookup", async (params) => {
|
|
|
131738
131886
|
await initialization;
|
|
131739
131887
|
return elementLookupProvider.elementLookup(params);
|
|
131740
131888
|
});
|
|
131889
|
+
connection.onRequest("sysml/validateText", async (params) => {
|
|
131890
|
+
await initialization;
|
|
131891
|
+
return textValidationProvider.validate(params);
|
|
131892
|
+
});
|
|
131741
131893
|
connection.onRequest("sysml/serverStats", () => {
|
|
131742
131894
|
const mem = typeof process !== "undefined" && typeof process.memoryUsage === "function" ? process.memoryUsage() : { heapUsed: 0, heapTotal: 0, rss: 0, external: 0 };
|
|
131743
131895
|
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.38.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",
|