Skip to content
This repository was archived by the owner on Mar 8, 2020. It is now read-only.

Commit 8f5725d

Browse files
m-g-kmbwhite
authored andcommitted
Update to latest composer-common and fix issues with circularly depenent model files. (#51)
Signed-off-by: m-g-k <[email protected]>
1 parent b63c98f commit 8f5725d

File tree

3 files changed

+147
-21
lines changed

3 files changed

+147
-21
lines changed

client/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
],
1212
"homepage": "https://hyperledger.github.io/composer/",
1313
"license": "Apache-2.0",
14-
"version": "0.15.0",
14+
"version": "0.15.1",
1515
"publisher": "HyperledgerComposer",
1616
"icon": "icon.png",
1717
"engines": {

server/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "composer-support-server",
33
"description": "HyperledgerComposer server",
4-
"version": "0.15.0",
4+
"version": "0.15.1",
55
"author": "Hyperledger Composer",
66
"publisher": "HyperledgerComposer",
77
"license": "Apache-2.0",

server/src/server.ts

Lines changed: 145 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ let documents: TextDocuments = new TextDocuments();
4242
// for open, change and close text document events
4343
documents.listen(connection);
4444

45-
4645
// After the server has started the client sends an initialize request. The server receives
4746
// in the passed params the rootPath of the workspace plus the client capabilities.
4847
let workspaceRoot: string;
@@ -72,9 +71,19 @@ connection.onInitialize((params): InitializeResult => {
7271
// The content of a text document has changed. This event is emitted
7372
// when the text document first opened or when its content has changed.
7473
documents.onDidChangeContent((doc) => {
74+
//connection.console.log("SERVER onDidChangeContent: " + doc.document.uri); //debug
7575
validateTextDocument(doc.document);
7676
});
7777

78+
documents.onDidOpen((doc) => {
79+
//connection.console.log("SERVER onDidOpen: " + doc.document.uri); //debug
80+
});
81+
82+
documents.onDidClose((doc) => {
83+
//connection.console.log("SERVER onDidClose: " + doc.document.uri); //debug
84+
closeTextDocument(doc.document);
85+
});
86+
7887
// The settings interface describes the server relevant settings part
7988
interface Settings {
8089
composer: ComposerSettings;
@@ -236,7 +245,7 @@ function handleGenerateUml(diagramTitle: string, originatingFileName: string) {
236245

237246
/**
238247
* Main method driven by the LSP when the user opens or changes a cto, acl or qry file
239-
* @param {string} textDocument - ".cto", "permissions.acl" or ".qry" document from the client to validate
248+
* @param {TextDocument} textDocument - ".cto", "permissions.acl" or ".qry" document from the client to validate
240249
*/
241250
function validateTextDocument(textDocument: TextDocument): void {
242251
let langId = textDocument.languageId; //type of file we are processing
@@ -268,52 +277,102 @@ function validateTextDocument(textDocument: TextDocument): void {
268277
validateExistingQueryModelFile(queryFile);
269278
}
270279
}
280+
} else {
281+
//clear any errors on the empty document
282+
sendDiagnosticSuccess(textDocument.uri); //all OK
271283
}
272284

273285
}
274286

275287
/**
276288
* Validates a cto file that the user has just opened or changed in the workspace.
277-
* @param {string} textDocument - ".cto" file to validate
289+
* @param {TextDocument} textDocument - ".cto" file to validate
278290
* @private
279291
*/
280292
function validateCtoModelFile(textDocument: TextDocument): void {
281293
try {
294+
//debug
295+
//var allNS = modelManager.getNamespaces();
296+
//connection.console.log("SERVER DOC-LEN: " + textDocument.getText().length); //debug
297+
//connection.console.log("SERVER ALL-NS: " + allNS.length); //debug
298+
//allNS.forEach(ns => {
299+
//connection.console.log("SERVER NS: " + ns); //debug
300+
//});
301+
282302
//hack to workaround circularly dependent documents
283-
let currentModels=[];
284-
documents.all().forEach( (textDocument: TextDocument) => {
285-
if (textDocument.languageId == "composer") {
286-
let model = new ModelFile(modelManager, textDocument.getText(), textDocument.uri);
287-
if (! modelManager.getModelFile(model.getNamespace())) {
288-
//only add if not existing
289-
currentModels.push(model);
303+
let currentModels = [];
304+
documents.all().forEach((doc: TextDocument) => {
305+
if (doc.languageId == "composer") {
306+
let modelContents = doc.getText(); //*.cto file
307+
if (modelContents.length > 0) {
308+
//cannot add 0 length documents
309+
try {
310+
let model: any = new ModelFile(modelManager, modelContents, doc.uri);
311+
model.lineCount = doc.lineCount; //store the count so future errors have access
312+
if (!modelManager.getModelFile(model.getNamespace())) {
313+
//only add if not existing and no error
314+
currentModels.push(model);
315+
}
316+
} catch (err) {
317+
//we had an error creating the model - output the error now
318+
//connection.console.log("SERVER model err early: " + err.toString() + " " + doc.uri); //debug
319+
buildAndSendDiagnosticFromException(err, doc.lineCount, doc.uri);
320+
}
290321
}
291322
}
292323
});
293-
//connection.console.log("SERVER addModelFiles: " + currentModels.length); //debug
294-
modelManager.addModelFiles(currentModels);
295324

325+
//connection.console.log("SERVER addModelFiles: " + currentModels.length); //debug
326+
if (currentModels.length > 0) {
327+
//only add if we have files or it forces a validation too early!
328+
try {
329+
modelManager.addModelFiles(currentModels);
330+
} catch (err) {
331+
//one of the files had an error validating, but the exception does not tell us which one so we must,
332+
//ignore errors adding files here and wait until the user selects the file in error to report it.
333+
//connection.console.log("SERVER model err adding: " + err.toString()); //debug
334+
}
335+
}
296336

297337
let modelContents = textDocument.getText(); //*.cto file
298338
//add or update, depending on existance. ModelFile and modelManager calls may throw an exception
299-
let model = new ModelFile(modelManager, modelContents, textDocument.uri);
300-
if (modelManager.getModelFile(model.getNamespace())) {
339+
let model: any = new ModelFile(modelManager, modelContents, textDocument.uri);
340+
model.lineCount = textDocument.lineCount; //store the count so future errors have access
341+
var existingModel = modelManager.getModelFile(model.getNamespace());
342+
if (existingModel && existingModel.getName() === textDocument.uri) {
343+
//update if we have a file that matches an existing namespace and filename
301344
//connection.console.log("SERVER update model: " + model.getNamespace()); //debug
302345
modelManager.updateModelFile(model);
303346
} else {
347+
//Composer does not allow two different files to belong to the same namespace, in which
348+
//case addModelFile() will throw for us when we add the second instance.
349+
//note, if we get here it will be because the file has an error or it would have been added above.
304350
//connection.console.log("SERVER add model: " + model.getNamespace()); //debug
305351
modelManager.addModelFile(model);
306352
}
307-
sendDiagnosticSuccess(textDocument.uri); //all OK
353+
354+
//finally check valiatation for cross validation for all additions and changes against other open models
355+
modelManager.getModelFiles().forEach(model => {
356+
try {
357+
model.validate();
358+
//clear any existing open errors against the file
359+
sendDiagnosticSuccess(model.getName()); //the name is the uri
360+
} catch (err) {
361+
//report any errors against the file
362+
buildAndSendDiagnosticFromException(err, model.lineCount, model.getName());
363+
}
364+
});
365+
366+
sendDiagnosticSuccess(textDocument.uri); //all OK for current document - probably unnecessary to report it again...
308367
} catch (err) {
309-
//connection.console.log("SERVER model err: " + err.toString()); //debug
368+
//connection.console.log("SERVER model err: " + err.toString() + " " + textDocument.uri); //debug
310369
buildAndSendDiagnosticFromException(err, textDocument.lineCount, textDocument.uri);
311370
}
312371
}
313372

314373
/**
315374
* Validates an acl file that the user has just opened or changed in the workspace.
316-
* @param {string} textDocument - new "permissions.acl" file to validate
375+
* @param {TextDocument} textDocument - new "permissions.acl" file to validate
317376
* @private
318377
*/
319378
function validateNewAclModelFile(textDocument: TextDocument): void {
@@ -345,7 +404,7 @@ function validateExistingAclModelFile(aclFile): void {
345404

346405
/**
347406
* Validates a qry file that the user has just opened or changed in the workspace.
348-
* @param {string} textDocument - new ".qry" file to validate
407+
* @param {TextDocument} textDocument - new ".qry" file to validate
349408
* @private
350409
*/
351410
function validateNewQueryModelFile(textDocument: TextDocument): void {
@@ -394,7 +453,7 @@ function buildAndSendDiagnosticFromException(err, lineCount: number, sourceURI:
394453

395454
//if it's a cto composer exception it will have a short message, but acl and qry ones do not
396455
if (typeof err.getShortMessage === "function") {
397-
//Short msg does not have and file and line info which is what we want
456+
//Short msg does not have any file and line info which is what we want
398457
fullMsg += err.getShortMessage();
399458
} else {
400459
//May have file and line info
@@ -465,6 +524,73 @@ function sendDiagnosticSuccess(sourceURI: string): void {
465524
connection.sendDiagnostics({ uri: sourceURI, diagnostics });
466525
}
467526

527+
/**
528+
* Main method driven by the LSP when the user closes a cto, acl or qry file
529+
* @param {TextDocument} textDocument - ".cto", "permissions.acl" or ".qry" document from the client to close
530+
*/
531+
function closeTextDocument(textDocument: TextDocument): void {
532+
let langId = textDocument.languageId; //type of file we are processing
533+
//note - this is the FULL document text as we can't do incremental yet!
534+
let txt = textDocument.getText();
535+
536+
//only care about files with data
537+
if (txt != null && txt.length > 0) {
538+
//different behaviour for each language type
539+
if (langId == "composer-acl") {
540+
//permissions.acl file
541+
//TODO - close acl file
542+
} else if (langId == "composer-qry") {
543+
//.qry file
544+
//TODO - close query file
545+
} else {
546+
//raw composer .cto file
547+
try {
548+
//It is possible the model file could have unparsable errors but will
549+
//handle this case another day (requires map of open files)
550+
let model: any = new ModelFile(modelManager, txt, textDocument.uri);
551+
var existingModel = modelManager.getModelFile(model.getNamespace());
552+
if (existingModel && existingModel.getName() === textDocument.uri) {
553+
//only delete if we match on namespace and name
554+
modelManager.deleteModelFile(model.getNamespace());
555+
} else {
556+
//clear any existing errors on the closed document, otherwise they are ophaned
557+
sendDiagnosticSuccess(textDocument.uri); //all OK
558+
}
559+
560+
//finally check valiatation for cross validation against other open models
561+
modelManager.getModelFiles().forEach(currrentModel => {
562+
try {
563+
currrentModel.validate();
564+
//clear any existing open errors against the file
565+
sendDiagnosticSuccess(currrentModel.getName()); //the name is the uri
566+
} catch (err) {
567+
//report any errors against the still open file
568+
buildAndSendDiagnosticFromException(err, currrentModel.lineCount, currrentModel.getName());
569+
}
570+
});
571+
} catch (err) {
572+
//ignore errors as we are closing the file.
573+
//connection.console.log("SERVER close err: " + err.toString() + " " + textDocument.uri); //debug
574+
}
575+
//if we have an acl file we should revalidate it incase the model changes broke something
576+
const aclFile = aclManager.getAclFile();
577+
if (aclFile != null) {
578+
validateExistingAclModelFile(aclFile);
579+
}
580+
581+
//if we have a query file we should revalidate it incase the model changes broke something
582+
const queryFile = queryManager.getQueryFile();
583+
if (queryFile != null) {
584+
validateExistingQueryModelFile(queryFile);
585+
}
586+
}
587+
} else {
588+
//clear any errors on the empty document
589+
sendDiagnosticSuccess(textDocument.uri); //all OK
590+
}
591+
592+
}
593+
468594
connection.onDidChangeWatchedFiles((change) => {
469595
// Monitored files have change in VSCode
470596
//connection.console.log('We received a file change event');

0 commit comments

Comments
 (0)