diff --git a/src/main/java/software/amazon/smithy/lsp/SmithyLanguageServer.java b/src/main/java/software/amazon/smithy/lsp/SmithyLanguageServer.java index be92de9..436c3f4 100644 --- a/src/main/java/software/amazon/smithy/lsp/SmithyLanguageServer.java +++ b/src/main/java/software/amazon/smithy/lsp/SmithyLanguageServer.java @@ -101,8 +101,10 @@ import software.amazon.smithy.lsp.document.Document; import software.amazon.smithy.lsp.document.DocumentParser; import software.amazon.smithy.lsp.document.DocumentShape; -import software.amazon.smithy.lsp.ext.serverstatus.OpenProject; -import software.amazon.smithy.lsp.ext.serverstatus.ServerStatus; +import software.amazon.smithy.lsp.ext.OpenProject; +import software.amazon.smithy.lsp.ext.SelectorParams; +import software.amazon.smithy.lsp.ext.ServerStatus; +import software.amazon.smithy.lsp.ext.SmithyProtocolExtensions; import software.amazon.smithy.lsp.handler.CompletionHandler; import software.amazon.smithy.lsp.handler.DefinitionHandler; import software.amazon.smithy.lsp.handler.FileWatcherRegistrationHandler; @@ -191,25 +193,22 @@ public void connect(LanguageClient client) { public CompletableFuture initialize(InitializeParams params) { LOGGER.finest("Initialize"); - // TODO: Use this to manage shutdown if the parent process exits, after upgrading jdk - // Optional.ofNullable(params.getProcessId()) - // .flatMap(ProcessHandle::of) - // .ifPresent(processHandle -> { - // processHandle.onExit().thenRun(this::exit); - // }); + Optional.ofNullable(params.getProcessId()) + .flatMap(ProcessHandle::of) + .ifPresent(processHandle -> processHandle.onExit().thenRun(this::exit)); // TODO: Replace with a Gson Type Adapter if more config options are added beyond `logToFile`. Object initializationOptions = params.getInitializationOptions(); - if (initializationOptions instanceof JsonObject) { - JsonObject jsonObject = (JsonObject) initializationOptions; + if (initializationOptions instanceof JsonObject jsonObject) { if (jsonObject.has("diagnostics.minimumSeverity")) { String configuredMinimumSeverity = jsonObject.get("diagnostics.minimumSeverity").getAsString(); Optional severity = Severity.fromString(configuredMinimumSeverity); if (severity.isPresent()) { this.minimumSeverity = severity.get(); } else { - client.error("Invalid value for 'diagnostics.minimumSeverity': " + configuredMinimumSeverity - + ".\nMust be one of " + Arrays.toString(Severity.values())); + client.error(String.format(""" + Invalid value for 'diagnostics.minimumSeverity': %s. + Must be one of %s.""", configuredMinimumSeverity, Arrays.toString(Severity.values()))); } } if (jsonObject.has("onlyReloadOnSave")) { @@ -365,7 +364,7 @@ public CompletableFuture> selectorCommand(SelectorParam LOGGER.finest("SelectorCommand"); Selector selector; try { - selector = Selector.parse(selectorParams.getExpression()); + selector = Selector.parse(selectorParams.expression()); } catch (Exception e) { LOGGER.info("Invalid selector"); // TODO: Respond with error somehow @@ -513,14 +512,15 @@ public void didChange(DidChangeTextDocumentParams params) { } if (!onlyReloadOnSave) { - // TODO: A consequence of this is that any existing validation events are cleared, which - // is kinda annoying. - // Report any parse/shape/trait loading errors Project project = projects.getProject(uri); if (project == null) { client.unknownFileError(uri, "change"); return; } + + // TODO: A consequence of this is that any existing validation events are cleared, which + // is kinda annoying. + // Report any parse/shape/trait loading errors CompletableFuture future = CompletableFuture .runAsync(() -> project.updateModelWithoutValidating(uri)) .thenComposeAsync(unused -> sendFileDiagnostics(uri)); @@ -628,10 +628,6 @@ public CompletableFuture resolveCompletionItem(CompletionItem un SmithyFile smithyFile = project.getSmithyFile(uri); return CompletableFutures.computeAsync((cc) -> { - if (smithyFile == null) { - return Collections.emptyList(); - } - Collection documentShapes = smithyFile.documentShapes(); if (documentShapes.isEmpty()) { return Collections.emptyList(); @@ -643,10 +639,6 @@ public CompletableFuture resolveCompletionItem(CompletionItem un List> documentSymbols = new ArrayList<>(documentShapes.size()); for (DocumentShape documentShape : documentShapes) { - if (cc.isCanceled()) { - client.info("canceled document symbols"); - return Collections.emptyList(); - } SymbolKind symbolKind; switch (documentShape.kind()) { case Inline: @@ -662,6 +654,11 @@ public CompletableFuture resolveCompletionItem(CompletionItem un symbolKind = SymbolKind.Class; break; } + + // Check before copying shapeName, which is actually a reference to the underlying document, and may + // be changed. + cc.checkCanceled(); + String symbolName = documentShape.shapeName().toString(); if (symbolName.isEmpty()) { LOGGER.warning("[DocumentSymbols] Empty shape name for " + documentShape); @@ -813,16 +810,11 @@ private static Diagnostic toDiagnostic(ValidationEvent validationEvent, SmithyFi } private static DiagnosticSeverity toDiagnosticSeverity(Severity severity) { - switch (severity) { - case ERROR: - case DANGER: - return DiagnosticSeverity.Error; - case WARNING: - return DiagnosticSeverity.Warning; - case NOTE: - return DiagnosticSeverity.Information; - default: - return DiagnosticSeverity.Hint; - } + return switch (severity) { + case ERROR, DANGER -> DiagnosticSeverity.Error; + case WARNING -> DiagnosticSeverity.Warning; + case NOTE -> DiagnosticSeverity.Information; + default -> DiagnosticSeverity.Hint; + }; } } diff --git a/src/main/java/software/amazon/smithy/lsp/codeactions/DefineVersionCodeAction.java b/src/main/java/software/amazon/smithy/lsp/codeactions/DefineVersionCodeAction.java index 02f17b1..a2e7d69 100644 --- a/src/main/java/software/amazon/smithy/lsp/codeactions/DefineVersionCodeAction.java +++ b/src/main/java/software/amazon/smithy/lsp/codeactions/DefineVersionCodeAction.java @@ -15,14 +15,12 @@ package software.amazon.smithy.lsp.codeactions; -import java.util.Collections; import java.util.List; import java.util.Map; import org.eclipse.lsp4j.CodeAction; -import org.eclipse.lsp4j.Position; -import org.eclipse.lsp4j.Range; import org.eclipse.lsp4j.TextEdit; import org.eclipse.lsp4j.WorkspaceEdit; +import software.amazon.smithy.lsp.protocol.LspAdapter; public final class DefineVersionCodeAction { private static final int DEFAULT_VERSION = 1; @@ -42,10 +40,9 @@ public static CodeAction build(String fileUri) { codeAction.setKind(SmithyCodeActions.SMITHY_DEFINE_VERSION); WorkspaceEdit wEdit = new WorkspaceEdit(); TextEdit edit = new TextEdit( - new Range(new Position(0, 0), new Position(0, 0)), - "$version: \"" + DEFAULT_VERSION + "\"\n\n" - ); - Map> changes = Collections.singletonMap(fileUri, Collections.singletonList(edit)); + LspAdapter.origin(), + String.format("$version: \"%s\"%n%n", DEFAULT_VERSION)); + Map> changes = Map.of(fileUri, List.of(edit)); wEdit.setChanges(changes); codeAction.setEdit(wEdit); return codeAction; diff --git a/src/main/java/software/amazon/smithy/lsp/codeactions/SmithyCodeActions.java b/src/main/java/software/amazon/smithy/lsp/codeactions/SmithyCodeActions.java index 3b8197f..115a435 100644 --- a/src/main/java/software/amazon/smithy/lsp/codeactions/SmithyCodeActions.java +++ b/src/main/java/software/amazon/smithy/lsp/codeactions/SmithyCodeActions.java @@ -62,11 +62,8 @@ public static List versionCodeActions(CodeActionParams params) { } Optional updateVersionDiagnostic = params.getContext().getDiagnostics().stream() .filter(diagnosticCodePredicate(SmithyDiagnostics.UPDATE_VERSION)).findFirst(); - if (updateVersionDiagnostic.isPresent()) { - actions.add( - UpdateVersionCodeAction.build(fileUri, updateVersionDiagnostic.get().getRange()) - ); - } + updateVersionDiagnostic.ifPresent(diagnostic -> actions.add( + UpdateVersionCodeAction.build(fileUri, diagnostic.getRange()))); return actions; } diff --git a/src/main/java/software/amazon/smithy/lsp/codeactions/UpdateVersionCodeAction.java b/src/main/java/software/amazon/smithy/lsp/codeactions/UpdateVersionCodeAction.java index 7e10a9a..2371499 100644 --- a/src/main/java/software/amazon/smithy/lsp/codeactions/UpdateVersionCodeAction.java +++ b/src/main/java/software/amazon/smithy/lsp/codeactions/UpdateVersionCodeAction.java @@ -15,7 +15,6 @@ package software.amazon.smithy.lsp.codeactions; -import java.util.Collections; import java.util.List; import java.util.Map; import org.eclipse.lsp4j.CodeAction; @@ -41,7 +40,7 @@ public static CodeAction build(String fileUri, Range versionStatementRange) { codeAction.setKind(SmithyCodeActions.SMITHY_UPDATE_VERSION); WorkspaceEdit wEdit = new WorkspaceEdit(); TextEdit edit = new TextEdit(versionStatementRange, "$version: \"" + LATEST_VERSION + "\""); - Map> changes = Collections.singletonMap(fileUri, Collections.singletonList(edit)); + Map> changes = Map.of(fileUri, List.of(edit)); wEdit.setChanges(changes); codeAction.setEdit(wEdit); return codeAction; diff --git a/src/main/java/software/amazon/smithy/lsp/document/Document.java b/src/main/java/software/amazon/smithy/lsp/document/Document.java index 8aa90d3..75ee0e1 100644 --- a/src/main/java/software/amazon/smithy/lsp/document/Document.java +++ b/src/main/java/software/amazon/smithy/lsp/document/Document.java @@ -322,7 +322,7 @@ public CharBuffer borrowId(Position position) { if (id == null) { return null; } - return id.borrowIdValue(); + return id.idSlice(); } /** diff --git a/src/main/java/software/amazon/smithy/lsp/document/DocumentId.java b/src/main/java/software/amazon/smithy/lsp/document/DocumentId.java index f2de2fe..ec7c5f3 100644 --- a/src/main/java/software/amazon/smithy/lsp/document/DocumentId.java +++ b/src/main/java/software/amazon/smithy/lsp/document/DocumentId.java @@ -12,8 +12,12 @@ * An inaccurate representation of an identifier within a model. It is * inaccurate in the sense that the string value it references isn't * necessarily a valid identifier, it just looks like an identifier. + * + * @param type The type of the id + * @param idSlice A borrowed slice containing the id's value + * @param range The range the id occupies */ -public final class DocumentId { +public record DocumentId(Type type, CharBuffer idSlice, Range range) { /** * Represents the different kinds of identifiers that can be used to match. */ @@ -41,32 +45,10 @@ public enum Type { /** * Same as {@link Type#ID}, but with a member - will have a {@code $}. */ - RELATIVE_WITH_MEMBER; - } - - private final Type type; - private final CharBuffer buffer; - private final Range range; - - DocumentId(Type type, CharBuffer buffer, Range range) { - this.type = type; - this.buffer = buffer; - this.range = range; - } - - public Type type() { - return type; + RELATIVE_WITH_MEMBER } public String copyIdValue() { - return buffer.toString(); - } - - public CharBuffer borrowIdValue() { - return buffer; - } - - public Range range() { - return range; + return idSlice.toString(); } } diff --git a/src/main/java/software/amazon/smithy/lsp/document/DocumentImports.java b/src/main/java/software/amazon/smithy/lsp/document/DocumentImports.java index 057aaa5..0c5d9c6 100644 --- a/src/main/java/software/amazon/smithy/lsp/document/DocumentImports.java +++ b/src/main/java/software/amazon/smithy/lsp/document/DocumentImports.java @@ -10,28 +10,8 @@ /** * The imports of a document, including the range they occupy. + * + * @param importsRange The range of the imports + * @param imports The set of imported shape ids. They are not guaranteed to be valid shape ids */ -public final class DocumentImports { - private final Range importsRange; - private final Set imports; - - DocumentImports(Range importsRange, Set imports) { - this.importsRange = importsRange; - this.imports = imports; - } - - /** - * @return The range of the imports - */ - public Range importsRange() { - return importsRange; - } - - /** - * @return The set of imported shape ids. They are not guaranteed - * to be valid shape ids - */ - public Set imports() { - return imports; - } -} +public record DocumentImports(Range importsRange, Set imports) {} diff --git a/src/main/java/software/amazon/smithy/lsp/document/DocumentNamespace.java b/src/main/java/software/amazon/smithy/lsp/document/DocumentNamespace.java index 52181a6..94c8b79 100644 --- a/src/main/java/software/amazon/smithy/lsp/document/DocumentNamespace.java +++ b/src/main/java/software/amazon/smithy/lsp/document/DocumentNamespace.java @@ -9,28 +9,8 @@ /** * The namespace of the document, including the range it occupies. + * + * @param statementRange The range of the statement, including {@code namespace} + * @param namespace The namespace of the document. Not guaranteed to be a valid namespace */ -public final class DocumentNamespace { - private final Range statementRange; - private final CharSequence namespace; - - DocumentNamespace(Range statementRange, CharSequence namespace) { - this.statementRange = statementRange; - this.namespace = namespace; - } - - /** - * @return The range of the statement, including {@code namespace} - */ - public Range statementRange() { - return statementRange; - } - - /** - * @return The namespace of the document. Not guaranteed to be - * a valid namespace - */ - public CharSequence namespace() { - return namespace; - } -} +public record DocumentNamespace(Range statementRange, CharSequence namespace) {} diff --git a/src/main/java/software/amazon/smithy/lsp/document/DocumentParser.java b/src/main/java/software/amazon/smithy/lsp/document/DocumentParser.java index f69d0f1..3982447 100644 --- a/src/main/java/software/amazon/smithy/lsp/document/DocumentParser.java +++ b/src/main/java/software/amazon/smithy/lsp/document/DocumentParser.java @@ -156,31 +156,23 @@ public Map documentShapes(Set shapes) { continue; } + DocumentShape documentShape; if (shape.isMemberShape()) { DocumentShape.Kind kind = DocumentShape.Kind.DefinedMember; if (is('$')) { kind = DocumentShape.Kind.Elided; } - DocumentShape member = documentShape(kind); - documentShapes.put(member.range().getStart(), member); - sp(); - if (peek() == ':') { - skip(); - // get target - sp(); - DocumentShape target = documentShape(DocumentShape.Kind.Targeted); - documentShapes.put(target.range().getStart(), target); - member.setTargetReference(target); - } + documentShape = documentShape(kind); } else { skipAlpha(); // shape type sp(); - DocumentShape shapeDef = documentShape(DocumentShape.Kind.DefinedShape); - if (shapeDef.shapeName().length() == 0) { - // Not sure if we should set the shape name here - shapeDef.setKind(DocumentShape.Kind.Inline); - } - documentShapes.put(shapeDef.range().getStart(), shapeDef); + documentShape = documentShape(DocumentShape.Kind.DefinedShape); + } + + documentShapes.put(documentShape.range().getStart(), documentShape); + if (documentShape.hasMemberTarget()) { + DocumentShape memberTarget = documentShape.targetReference(); + documentShapes.put(memberTarget.range().getStart(), memberTarget); } } return documentShapes; @@ -198,7 +190,21 @@ private DocumentShape documentShape(DocumentShape.Kind kind) { int endIdx = position(); Range range = new Range(start, end); CharSequence shapeName = document.borrowSpan(startIdx, endIdx); - return new DocumentShape(range, shapeName, kind); + + // This is a bit ugly, but it avoids intermediate allocations (like a builder would require) + DocumentShape targetReference = null; + if (kind == DocumentShape.Kind.DefinedMember) { + sp(); + if (is(':')) { + skip(); + sp(); + targetReference = documentShape(DocumentShape.Kind.Targeted); + } + } else if (kind == DocumentShape.Kind.DefinedShape && (shapeName == null || shapeName.isEmpty())) { + kind = DocumentShape.Kind.Inline; + } + + return new DocumentShape(range, shapeName, kind, targetReference); } /** @@ -604,15 +610,10 @@ private boolean isSp() { private boolean isWs(int offset) { char peeked = peek(offset); - switch (peeked) { - case '\n': - case '\r': - case ' ': - case '\t': - return true; - default: - return false; - } + return switch (peeked) { + case '\n', '\r', ' ', '\t' -> true; + default -> false; + }; } private boolean isEof() { @@ -643,33 +644,12 @@ private boolean isShapeType() { return false; } - switch (token.toString()) { - case "structure": - case "operation": - case "string": - case "integer": - case "list": - case "map": - case "boolean": - case "enum": - case "union": - case "blob": - case "byte": - case "short": - case "long": - case "float": - case "double": - case "timestamp": - case "intEnum": - case "document": - case "service": - case "resource": - case "bigDecimal": - case "bigInteger": - return true; - default: - return false; - } + return switch (token.toString()) { + case "structure", "operation", "string", "integer", "list", "map", "boolean", "enum", "union", "blob", + "byte", "short", "long", "float", "double", "timestamp", "intEnum", "document", "service", + "resource", "bigDecimal", "bigInteger" -> true; + default -> false; + }; } private int firstIndexOfWithOnlyLeadingWs(String s) { diff --git a/src/main/java/software/amazon/smithy/lsp/document/DocumentPositionContext.java b/src/main/java/software/amazon/smithy/lsp/document/DocumentPositionContext.java index d961bdd..e300733 100644 --- a/src/main/java/software/amazon/smithy/lsp/document/DocumentPositionContext.java +++ b/src/main/java/software/amazon/smithy/lsp/document/DocumentPositionContext.java @@ -40,5 +40,5 @@ public enum DocumentPositionContext { /** * An unknown or indeterminate position. */ - OTHER; + OTHER } diff --git a/src/main/java/software/amazon/smithy/lsp/document/DocumentShape.java b/src/main/java/software/amazon/smithy/lsp/document/DocumentShape.java index 6ea1b4d..1fe748e 100644 --- a/src/main/java/software/amazon/smithy/lsp/document/DocumentShape.java +++ b/src/main/java/software/amazon/smithy/lsp/document/DocumentShape.java @@ -5,7 +5,6 @@ package software.amazon.smithy.lsp.document; -import java.util.Objects; import org.eclipse.lsp4j.Range; /** @@ -15,42 +14,12 @@ * corresponding to a specific {@link Kind}. For each kind, the range spans the * shape name/id only. */ -public final class DocumentShape { - private final Range range; - private final CharSequence shapeName; - private Kind kind; - private DocumentShape targetReference; - - DocumentShape(Range range, CharSequence shapeName, Kind kind) { - this.range = range; - this.shapeName = shapeName; - this.kind = kind; - } - - public Range range() { - return range; - } - - public CharSequence shapeName() { - return shapeName; - } - - public Kind kind() { - return kind; - } - - void setKind(Kind kind) { - this.kind = kind; - } - - public DocumentShape targetReference() { - return targetReference; - } - - void setTargetReference(DocumentShape targetReference) { - this.targetReference = targetReference; - } - +public record DocumentShape( + Range range, + CharSequence shapeName, + Kind kind, + DocumentShape targetReference +) { public boolean isKind(Kind other) { return this.kind.equals(other); } @@ -59,33 +28,6 @@ public boolean hasMemberTarget() { return isKind(Kind.DefinedMember) && targetReference() != null; } - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - DocumentShape that = (DocumentShape) o; - return Objects.equals(range, that.range) && Objects.equals(shapeName, that.shapeName) && kind == that.kind; - } - - @Override - public int hashCode() { - return Objects.hash(range, shapeName, kind); - } - - @Override - public String toString() { - return "DocumentShape{" - + "range=" + range - + ", shapeName=" + shapeName - + ", kind=" + kind - + ", targetReference=" + targetReference - + '}'; - } - /** * The different kinds of {@link DocumentShape}s that can exist, corresponding to places * that a shape definition or reference may appear. This is non-exhaustive (for now). @@ -95,6 +37,6 @@ public enum Kind { DefinedMember, Elided, Targeted, - Inline; + Inline } } diff --git a/src/main/java/software/amazon/smithy/lsp/document/DocumentVersion.java b/src/main/java/software/amazon/smithy/lsp/document/DocumentVersion.java index 308bdeb..da710cc 100644 --- a/src/main/java/software/amazon/smithy/lsp/document/DocumentVersion.java +++ b/src/main/java/software/amazon/smithy/lsp/document/DocumentVersion.java @@ -9,27 +9,8 @@ /** * The Smithy version of the document, including the range it occupies. + * + * @param range The range of the version statement + * @param version The literal text of the version value */ -public final class DocumentVersion { - private final Range range; - private final String version; - - DocumentVersion(Range range, String version) { - this.range = range; - this.version = version; - } - - /** - * @return The range of the version statement - */ - public Range range() { - return range; - } - - /** - * @return The literal text of the version value - */ - public String version() { - return version; - } -} +public record DocumentVersion(Range range, String version) {} diff --git a/src/main/java/software/amazon/smithy/lsp/ext/OpenProject.java b/src/main/java/software/amazon/smithy/lsp/ext/OpenProject.java new file mode 100644 index 0000000..14a0975 --- /dev/null +++ b/src/main/java/software/amazon/smithy/lsp/ext/OpenProject.java @@ -0,0 +1,18 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.lsp.ext; + +import java.util.List; +import org.eclipse.lsp4j.jsonrpc.validation.NonNull; + +/** + * A snapshot of a project the server has open. + * + * @param root The root URI of the project + * @param files The list of all file URIs tracked by the project + * @param isDetached Whether the project is detached - tracking just a single open file + */ +public record OpenProject(@NonNull String root, @NonNull List files, boolean isDetached) {} diff --git a/src/main/java/software/amazon/smithy/lsp/SelectorParams.java b/src/main/java/software/amazon/smithy/lsp/ext/SelectorParams.java similarity index 62% rename from src/main/java/software/amazon/smithy/lsp/SelectorParams.java rename to src/main/java/software/amazon/smithy/lsp/ext/SelectorParams.java index e285b5e..e5c4fb1 100644 --- a/src/main/java/software/amazon/smithy/lsp/SelectorParams.java +++ b/src/main/java/software/amazon/smithy/lsp/ext/SelectorParams.java @@ -13,20 +13,15 @@ * permissions and limitations under the License. */ -package software.amazon.smithy.lsp; +package software.amazon.smithy.lsp.ext; -import org.eclipse.lsp4j.jsonrpc.util.Preconditions; import org.eclipse.lsp4j.jsonrpc.validation.NonNull; -public class SelectorParams { - @NonNull - private final String expression; - - public SelectorParams(@NonNull final String selector) { - this.expression = Preconditions.checkNotNull(selector, "selector"); - } +/** + * Input to the {@link SmithyProtocolExtensions#selectorCommand(SelectorParams)} + * request. + * + * @param expression The selector expression to execute + */ +public record SelectorParams(@NonNull String expression) {} - public String getExpression() { - return this.expression; - } -} diff --git a/src/main/java/software/amazon/smithy/lsp/ext/ServerStatus.java b/src/main/java/software/amazon/smithy/lsp/ext/ServerStatus.java new file mode 100644 index 0000000..42e1417 --- /dev/null +++ b/src/main/java/software/amazon/smithy/lsp/ext/ServerStatus.java @@ -0,0 +1,17 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.lsp.ext; + +import java.util.List; +import org.eclipse.lsp4j.jsonrpc.validation.NonNull; + +/** + * A snapshot of the server status, containing the projects it has open. + * We can add more here later as we see fit. + * + * @param openProjects The open projects tracked by the server + */ +public record ServerStatus(@NonNull List openProjects) {} diff --git a/src/main/java/software/amazon/smithy/lsp/SmithyProtocolExtensions.java b/src/main/java/software/amazon/smithy/lsp/ext/SmithyProtocolExtensions.java similarity index 93% rename from src/main/java/software/amazon/smithy/lsp/SmithyProtocolExtensions.java rename to src/main/java/software/amazon/smithy/lsp/ext/SmithyProtocolExtensions.java index 3a26391..37d2c0a 100644 --- a/src/main/java/software/amazon/smithy/lsp/SmithyProtocolExtensions.java +++ b/src/main/java/software/amazon/smithy/lsp/ext/SmithyProtocolExtensions.java @@ -13,7 +13,7 @@ * permissions and limitations under the License. */ -package software.amazon.smithy.lsp; +package software.amazon.smithy.lsp.ext; import java.util.List; import java.util.concurrent.CompletableFuture; @@ -21,7 +21,6 @@ import org.eclipse.lsp4j.TextDocumentIdentifier; import org.eclipse.lsp4j.jsonrpc.services.JsonRequest; import org.eclipse.lsp4j.jsonrpc.services.JsonSegment; -import software.amazon.smithy.lsp.ext.serverstatus.ServerStatus; /** * Interface for protocol extensions for Smithy. diff --git a/src/main/java/software/amazon/smithy/lsp/ext/serverstatus/OpenProject.java b/src/main/java/software/amazon/smithy/lsp/ext/serverstatus/OpenProject.java deleted file mode 100644 index 3eaf45d..0000000 --- a/src/main/java/software/amazon/smithy/lsp/ext/serverstatus/OpenProject.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -package software.amazon.smithy.lsp.ext.serverstatus; - -import java.util.List; -import org.eclipse.lsp4j.jsonrpc.validation.NonNull; - -/** - * A snapshot of a project the server has open. - */ -public class OpenProject { - @NonNull - private final String root; - @NonNull - private final List files; - private final boolean isDetached; - - /** - * @param root The root URI of the project - * @param files The list of all file URIs tracked by the project - * @param isDetached Whether the project is detached - */ - public OpenProject(@NonNull final String root, @NonNull final List files, boolean isDetached) { - this.root = root; - this.files = files; - this.isDetached = isDetached; - } - - /** - * @return The root directory of the project - */ - public String root() { - return root; - } - - /** - * @return The list of all file URIs tracked by the project - */ - public List files() { - return files; - } - - /** - * @return Whether the project is detached - tracking just a single open file - */ - public boolean isDetached() { - return isDetached; - } -} diff --git a/src/main/java/software/amazon/smithy/lsp/ext/serverstatus/ServerStatus.java b/src/main/java/software/amazon/smithy/lsp/ext/serverstatus/ServerStatus.java deleted file mode 100644 index 4137272..0000000 --- a/src/main/java/software/amazon/smithy/lsp/ext/serverstatus/ServerStatus.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -package software.amazon.smithy.lsp.ext.serverstatus; - -import java.util.List; -import org.eclipse.lsp4j.jsonrpc.validation.NonNull; - -/** - * A snapshot of the server status, containing the projects it has open. - * We can add more here later as we see fit. - */ -public class ServerStatus { - @NonNull - private final List openProjects; - - public ServerStatus(@NonNull final List openProjects) { - this.openProjects = openProjects; - } - - /** - * @return The open projects tracked by the server - */ - public List openProjects() { - return openProjects; - } -} diff --git a/src/main/java/software/amazon/smithy/lsp/handler/CompletionHandler.java b/src/main/java/software/amazon/smithy/lsp/handler/CompletionHandler.java index 8720840..874cb04 100644 --- a/src/main/java/software/amazon/smithy/lsp/handler/CompletionHandler.java +++ b/src/main/java/software/amazon/smithy/lsp/handler/CompletionHandler.java @@ -11,6 +11,7 @@ import java.util.List; import java.util.Optional; import java.util.function.BiConsumer; +import java.util.function.Consumer; import java.util.function.Predicate; import java.util.stream.Stream; import org.eclipse.lsp4j.CompletionContext; @@ -97,7 +98,7 @@ public List handle(CompletionParams params, CancelChecker cc) { // TODO: Maybe we should only copy the token up to the current character DocumentId id = smithyFile.document().copyDocumentId(position); - if (id == null || id.borrowIdValue().length() == 0) { + if (id == null || id.idSlice().isEmpty()) { return Collections.emptyList(); } @@ -106,7 +107,7 @@ public List handle(CompletionParams params, CancelChecker cc) { } Optional modelResult = project.modelResult().getResult(); - if (!modelResult.isPresent()) { + if (modelResult.isEmpty()) { return Collections.emptyList(); } Model model = modelResult.get(); @@ -119,11 +120,11 @@ public List handle(CompletionParams params, CancelChecker cc) { return contextualShapes(model, context, smithyFile) .filter(contextualMatcher(id, context)) - // TODO: Use mapMulti when we upgrade jdk>16 - .collect(ArrayList::new, completionsFactory(context, model, smithyFile, id), ArrayList::addAll); + .mapMulti(completionsFactory(context, model, smithyFile, id)) + .toList(); } - private static BiConsumer, Shape> completionsFactory( + private static BiConsumer> completionsFactory( DocumentPositionContext context, Model model, SmithyFile smithyFile, @@ -131,13 +132,13 @@ private static BiConsumer, Shape> completionsFactory( ) { TraitBodyVisitor visitor = new TraitBodyVisitor(model); boolean useFullId = shouldMatchOnAbsoluteId(id, context); - return (acc, shape) -> { + return (shape, consumer) -> { String shapeLabel = useFullId ? shape.getId().toString() : shape.getId().getName(); switch (context) { - case TRAIT: + case TRAIT -> { String traitBody = shape.accept(visitor); // Strip outside pair of brackets from any structure traits. if (!traitBody.isEmpty() && traitBody.charAt(0) == '{') { @@ -147,25 +148,21 @@ private static BiConsumer, Shape> completionsFactory( if (!traitBody.isEmpty()) { CompletionItem traitWithMembersItem = createCompletion( shapeLabel + "(" + traitBody + ")", shape.getId(), smithyFile, useFullId, id); - acc.add(traitWithMembersItem); + consumer.accept(traitWithMembersItem); } if (shape.isStructureShape() && !shape.members().isEmpty()) { shapeLabel += "()"; } - CompletionItem defaultCompletionItem = createCompletion( - shapeLabel, shape.getId(), smithyFile, useFullId, id); - acc.add(defaultCompletionItem); - break; - case MEMBER_TARGET: - case MIXIN: - case USE_TARGET: - acc.add(createCompletion(shapeLabel, shape.getId(), smithyFile, useFullId, id)); - break; - case SHAPE_DEF: - case OTHER: - default: - break; + CompletionItem defaultItem = createCompletion(shapeLabel, shape.getId(), smithyFile, useFullId, id); + consumer.accept(defaultItem); + } + case MEMBER_TARGET, MIXIN, USE_TARGET -> { + CompletionItem item = createCompletion(shapeLabel, shape.getId(), smithyFile, useFullId, id); + consumer.accept(item); + } + default -> { + } } }; } @@ -204,25 +201,18 @@ private static TextEdit getImportTextEdit(SmithyFile smithyFile, String importId } private static Stream contextualShapes(Model model, DocumentPositionContext context, SmithyFile smithyFile) { - switch (context) { - case TRAIT: - return model.getShapesWithTrait(TraitDefinition.class).stream(); - case MEMBER_TARGET: - return model.shapes() - .filter(shape -> !shape.isMemberShape()) - .filter(shape -> !shape.hasTrait(TraitDefinition.class)); - case MIXIN: - return model.getShapesWithTrait(MixinTrait.class).stream(); - case USE_TARGET: - return model.shapes() - .filter(shape -> !shape.isMemberShape()) - .filter(shape -> !shape.getId().getNamespace().contentEquals(smithyFile.namespace())) - .filter(shape -> !smithyFile.hasImport(shape.getId().toString())); - case SHAPE_DEF: - case OTHER: - default: - return Stream.empty(); - } + return switch (context) { + case TRAIT -> model.getShapesWithTrait(TraitDefinition.class).stream(); + case MEMBER_TARGET -> model.shapes() + .filter(shape -> !shape.isMemberShape()) + .filter(shape -> !shape.hasTrait(TraitDefinition.class)); + case MIXIN -> model.getShapesWithTrait(MixinTrait.class).stream(); + case USE_TARGET -> model.shapes() + .filter(shape -> !shape.isMemberShape()) + .filter(shape -> !shape.getId().getNamespace().contentEquals(smithyFile.namespace())) + .filter(shape -> !smithyFile.hasImport(shape.getId().toString())); + default -> Stream.empty(); + }; } private static Predicate contextualMatcher(DocumentId id, DocumentPositionContext context) { diff --git a/src/main/java/software/amazon/smithy/lsp/handler/DefinitionHandler.java b/src/main/java/software/amazon/smithy/lsp/handler/DefinitionHandler.java index a3deb37..264960c 100644 --- a/src/main/java/software/amazon/smithy/lsp/handler/DefinitionHandler.java +++ b/src/main/java/software/amazon/smithy/lsp/handler/DefinitionHandler.java @@ -44,12 +44,12 @@ public DefinitionHandler(Project project, SmithyFile smithyFile) { public List handle(DefinitionParams params) { Position position = params.getPosition(); DocumentId id = smithyFile.document().copyDocumentId(position); - if (id == null || id.borrowIdValue().length() == 0) { + if (id == null || id.idSlice().isEmpty()) { return Collections.emptyList(); } Optional modelResult = project.modelResult().getResult(); - if (!modelResult.isPresent()) { + if (modelResult.isEmpty()) { return Collections.emptyList(); } @@ -78,19 +78,13 @@ private static Predicate contextualMatcher(SmithyFile smithyFile, Documen } private static Stream contextualShapes(Model model, DocumentPositionContext context) { - switch (context) { - case TRAIT: - return model.getShapesWithTrait(TraitDefinition.class).stream(); - case MEMBER_TARGET: - return model.shapes() - .filter(shape -> !shape.isMemberShape()) - .filter(shape -> !shape.hasTrait(TraitDefinition.class)); - case MIXIN: - return model.getShapesWithTrait(MixinTrait.class).stream(); - case SHAPE_DEF: - case OTHER: - default: - return model.shapes().filter(shape -> !shape.isMemberShape()); - } + return switch (context) { + case TRAIT -> model.getShapesWithTrait(TraitDefinition.class).stream(); + case MEMBER_TARGET -> model.shapes() + .filter(shape -> !shape.isMemberShape()) + .filter(shape -> !shape.hasTrait(TraitDefinition.class)); + case MIXIN -> model.getShapesWithTrait(MixinTrait.class).stream(); + default -> model.shapes().filter(shape -> !shape.isMemberShape()); + }; } } diff --git a/src/main/java/software/amazon/smithy/lsp/handler/HoverHandler.java b/src/main/java/software/amazon/smithy/lsp/handler/HoverHandler.java index fdf4d06..d0cf640 100644 --- a/src/main/java/software/amazon/smithy/lsp/handler/HoverHandler.java +++ b/src/main/java/software/amazon/smithy/lsp/handler/HoverHandler.java @@ -5,15 +5,13 @@ package software.amazon.smithy.lsp.handler; -import static java.util.regex.Matcher.quoteReplacement; - import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; import java.util.Map; import java.util.Optional; import java.util.function.Predicate; -import java.util.stream.Collectors; +import java.util.regex.Matcher; import java.util.stream.Stream; import org.eclipse.lsp4j.Hover; import org.eclipse.lsp4j.HoverParams; @@ -64,12 +62,12 @@ public Hover handle(HoverParams params, Severity minimumSeverity) { Hover hover = emptyContents(); Position position = params.getPosition(); DocumentId id = smithyFile.document().copyDocumentId(position); - if (id == null || id.borrowIdValue().length() == 0) { + if (id == null || id.idSlice().isEmpty()) { return hover; } ValidatedResult modelResult = project.modelResult(); - if (!modelResult.getResult().isPresent()) { + if (modelResult.getResult().isEmpty()) { return hover; } @@ -80,7 +78,7 @@ public Hover handle(HoverParams params, Severity minimumSeverity) { .filter(contextualMatcher(smithyFile, id)) .findFirst(); - if (!matchingShape.isPresent()) { + if (matchingShape.isEmpty()) { return hover; } @@ -107,7 +105,7 @@ public Hover handle(HoverParams params, Severity minimumSeverity) { .filter(event -> event.getShapeId().isPresent()) .filter(event -> event.getShapeId().get().equals(shapeToSerialize.getId())) .filter(event -> event.getSeverity().compareTo(minimumSeverity) >= 0) - .collect(Collectors.toList()); + .toList(); if (!validationEvents.isEmpty()) { for (ValidationEvent event : validationEvents) { hoverContent.append("**") @@ -116,20 +114,24 @@ public Hover handle(HoverParams params, Severity minimumSeverity) { .append(": ") .append(event.getMessage()); } - hoverContent.append("\n\n---\n\n"); + hoverContent.append(System.lineSeparator()) + .append(System.lineSeparator()) + .append("---") + .append(System.lineSeparator()) + .append(System.lineSeparator()); } String serializedShape = serialized.get(path) .substring(15) // remove '$version: "2.0"' .trim() - .replaceAll(quoteReplacement("\n\n"), "\n"); - int eol = serializedShape.indexOf('\n'); - String namespaceLine = serializedShape.substring(0, eol); - serializedShape = serializedShape.substring(eol + 1); - hoverContent.append(String.format("```smithy\n" - + "%s\n" - + "%s\n" - + "```\n", namespaceLine, serializedShape)); + .replaceAll(Matcher.quoteReplacement( + // Replace newline literals with actual newlines + System.lineSeparator() + System.lineSeparator()), System.lineSeparator()); + hoverContent.append(String.format(""" + ```smithy + %s + ``` + """, serializedShape)); // TODO: Add docs to a separate section of the hover content // if (shapeToSerialize.hasTrait(DocumentationTrait.class)) { @@ -155,19 +157,13 @@ private static Predicate contextualMatcher(SmithyFile smithyFile, Documen } private Stream contextualShapes(Model model, DocumentPositionContext context) { - switch (context) { - case TRAIT: - return model.getShapesWithTrait(TraitDefinition.class).stream(); - case MEMBER_TARGET: - return model.shapes() - .filter(shape -> !shape.isMemberShape()) - .filter(shape -> !shape.hasTrait(TraitDefinition.class)); - case MIXIN: - return model.getShapesWithTrait(MixinTrait.class).stream(); - case SHAPE_DEF: - case OTHER: - default: - return model.shapes().filter(shape -> !shape.isMemberShape()); - } + return switch (context) { + case TRAIT -> model.getShapesWithTrait(TraitDefinition.class).stream(); + case MEMBER_TARGET -> model.shapes() + .filter(shape -> !shape.isMemberShape()) + .filter(shape -> !shape.hasTrait(TraitDefinition.class)); + case MIXIN -> model.getShapesWithTrait(MixinTrait.class).stream(); + default -> model.shapes().filter(shape -> !shape.isMemberShape()); + }; } } diff --git a/src/main/java/software/amazon/smithy/lsp/project/Project.java b/src/main/java/software/amazon/smithy/lsp/project/Project.java index bd65d28..42c9135 100644 --- a/src/main/java/software/amazon/smithy/lsp/project/Project.java +++ b/src/main/java/software/amazon/smithy/lsp/project/Project.java @@ -187,7 +187,7 @@ public void updateFiles(Set addUris, Set removeUris) { * @param validate Whether to run model validation. */ public void updateFiles(Set addUris, Set removeUris, Set changeUris, boolean validate) { - if (!modelResult.getResult().isPresent()) { + if (modelResult.getResult().isEmpty()) { // TODO: If there's no model, we didn't collect the smithy files (so no document), so I'm thinking // maybe we do nothing here. But we could also still update the document, and // just compute the shapes later? @@ -280,8 +280,7 @@ public void updateFiles(Set addUris, Set removeUris, Set String path = LspAdapter.toPath(uri); Set fileShapes = getFileShapes(path, Collections.emptySet()); Document document = Document.of(IoUtils.readUtf8File(path)); - SmithyFile smithyFile = ProjectLoader.buildSmithyFile(path, document, fileShapes) - .build(); + SmithyFile smithyFile = ProjectLoader.buildSmithyFile(path, document, fileShapes).build(); smithyFiles.put(path, smithyFile); } } @@ -335,9 +334,8 @@ private void removeDependentsForReload( // the file would be fine because it would ignore the duplicated trait application coming from the same // source location. But if the apply statement is changed/removed, the old application isn't removed, so we // could get a duplicate trait, or a merged array trait. - smithyFileDependenciesIndex.getDependentFiles(path).forEach((depPath) -> { - removeFileForReload(assembler, builder, depPath, visited); - }); + smithyFileDependenciesIndex.getDependentFiles(path).forEach((depPath) -> + removeFileForReload(assembler, builder, depPath, visited)); smithyFileDependenciesIndex.getAppliedTraitsInFile(path).forEach((shapeId, traits) -> { Shape shape = builder.getCurrentShapes().get(shapeId); if (shape != null) { diff --git a/src/main/java/software/amazon/smithy/lsp/project/ProjectDependency.java b/src/main/java/software/amazon/smithy/lsp/project/ProjectDependency.java index a6e5347..0c5fd65 100644 --- a/src/main/java/software/amazon/smithy/lsp/project/ProjectDependency.java +++ b/src/main/java/software/amazon/smithy/lsp/project/ProjectDependency.java @@ -11,34 +11,15 @@ /** * An arbitrary project dependency, used to specify non-maven dependencies * that exist locally. + * + * @param name The name of the dependency + * @param path The path of the dependency */ -final class ProjectDependency { - private final String name; - private final String path; - - private ProjectDependency(String name, String path) { - this.name = name; - this.path = path; - } - +record ProjectDependency(String name, String path) { static ProjectDependency fromNode(Node node) { ObjectNode objectNode = node.expectObjectNode(); String name = objectNode.expectStringMember("name").getValue(); String path = objectNode.expectStringMember("path").getValue(); return new ProjectDependency(name, path); } - - /** - * @return The name of the dependency - */ - public String name() { - return name; - } - - /** - * @return The path of the dependency - */ - public String path() { - return path; - } } diff --git a/src/main/java/software/amazon/smithy/lsp/project/ProjectLoader.java b/src/main/java/software/amazon/smithy/lsp/project/ProjectLoader.java index b7f23ee..cc4f8c6 100644 --- a/src/main/java/software/amazon/smithy/lsp/project/ProjectLoader.java +++ b/src/main/java/software/amazon/smithy/lsp/project/ProjectLoader.java @@ -88,7 +88,8 @@ public static Project loadDetached(String uri, String text) { if (LspAdapter.isSmithyJarFile(filePath) || LspAdapter.isJarFile(filePath)) { return Document.of(IoUtils.readUtf8Url(LspAdapter.jarUrl(filePath))); } else if (filePath.equals(asPath)) { - return Document.of(text); + Document document = Document.of(text); + return document; } else { // TODO: Make generic 'please file a bug report' exception throw new IllegalStateException( @@ -378,7 +379,7 @@ private static void collectDirectory(List accumulator, Path root, Path cur } } - private static void collectJar(List accumulator, String jarRoot, Path jarPath) throws IOException { + private static void collectJar(List accumulator, String jarRoot, Path jarPath) { URL manifestUrl = ModelDiscovery.createSmithyJarManifestUrl(jarPath.toString()); String prefix = computeJarFilePrefix(jarRoot, jarPath); diff --git a/src/main/java/software/amazon/smithy/lsp/project/SmithyBuildExtensions.java b/src/main/java/software/amazon/smithy/lsp/project/SmithyBuildExtensions.java index 211a908..83af09b 100644 --- a/src/main/java/software/amazon/smithy/lsp/project/SmithyBuildExtensions.java +++ b/src/main/java/software/amazon/smithy/lsp/project/SmithyBuildExtensions.java @@ -129,7 +129,7 @@ public Builder merge(SmithyBuildExtensions other) { if (other.mavenConfig().getRepositories().isEmpty()) { repositories.addAll(other.mavenRepositories.stream() .map(repo -> MavenRepository.builder().url(repo).build()) - .collect(Collectors.toList())); + .toList()); } else { repositories.addAll(other.maven.getRepositories()); } diff --git a/src/main/java/software/amazon/smithy/lsp/project/SmithyFileDependenciesIndex.java b/src/main/java/software/amazon/smithy/lsp/project/SmithyFileDependenciesIndex.java index f9c939e..f6652c1 100644 --- a/src/main/java/software/amazon/smithy/lsp/project/SmithyFileDependenciesIndex.java +++ b/src/main/java/software/amazon/smithy/lsp/project/SmithyFileDependenciesIndex.java @@ -82,7 +82,7 @@ List getTraitsAppliedInOtherFiles(ToShapeId toShapeId) { // TODO: Make this take care of metadata too static SmithyFileDependenciesIndex compute(ValidatedResult modelResult) { - if (!modelResult.getResult().isPresent()) { + if (modelResult.getResult().isEmpty()) { return new SmithyFileDependenciesIndex(); } diff --git a/src/main/java/software/amazon/smithy/lsp/protocol/LspAdapter.java b/src/main/java/software/amazon/smithy/lsp/protocol/LspAdapter.java index 51e4ce8..59e62ea 100644 --- a/src/main/java/software/amazon/smithy/lsp/protocol/LspAdapter.java +++ b/src/main/java/software/amazon/smithy/lsp/protocol/LspAdapter.java @@ -6,7 +6,6 @@ package software.amazon.smithy.lsp.protocol; import java.io.IOException; -import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URL; import java.net.URLDecoder; @@ -200,13 +199,8 @@ public static URL jarUrl(String uriOrPath) { } private static String decode(String uriOrPath) { - try { - // Some clients encode parts of the jar, like !/ - return URLDecoder.decode(uriOrPath, StandardCharsets.UTF_8.name()); - } catch (UnsupportedEncodingException e) { - LOGGER.severe("Failed to decode " + uriOrPath + " : " + e.getMessage()); - return uriOrPath; - } + // Some clients encode parts of the jar, like !/ + return URLDecoder.decode(uriOrPath, StandardCharsets.UTF_8); } private static String fixJarScheme(String uriOrPath) { diff --git a/src/main/java/software/amazon/smithy/lsp/util/Result.java b/src/main/java/software/amazon/smithy/lsp/util/Result.java index 8ee93e6..d4c4112 100644 --- a/src/main/java/software/amazon/smithy/lsp/util/Result.java +++ b/src/main/java/software/amazon/smithy/lsp/util/Result.java @@ -89,7 +89,7 @@ public boolean isErr() { * @return The successful value, or throw an exception if this Result is failed */ public T unwrap() { - if (!get().isPresent()) { + if (get().isEmpty()) { throw new RuntimeException("Called unwrap on an Err Result: " + getErr().get()); } return get().get(); @@ -99,7 +99,7 @@ public T unwrap() { * @return The failed value, or throw an exception if this Result is successful */ public E unwrapErr() { - if (!getErr().isPresent()) { + if (getErr().isEmpty()) { throw new RuntimeException("Called unwrapErr on an Ok Result: " + get().get()); } return getErr().get(); diff --git a/src/test/java/software/amazon/smithy/lsp/LspMatchers.java b/src/test/java/software/amazon/smithy/lsp/LspMatchers.java index be51d9c..4048b74 100644 --- a/src/test/java/software/amazon/smithy/lsp/LspMatchers.java +++ b/src/test/java/software/amazon/smithy/lsp/LspMatchers.java @@ -21,7 +21,7 @@ public final class LspMatchers { private LspMatchers() {} public static Matcher hasLabel(String label) { - return new CustomTypeSafeMatcher("a completion item with the label + `" + label + "`") { + return new CustomTypeSafeMatcher<>("a completion item with the label + `" + label + "`") { @Override protected boolean matchesSafely(CompletionItem item) { return item.getLabel().equals(label); @@ -36,7 +36,7 @@ public void describeMismatchSafely(CompletionItem item, Description description) } public static Matcher makesEditedDocument(Document document, String expected) { - return new CustomTypeSafeMatcher("makes an edited document " + expected) { + return new CustomTypeSafeMatcher<>("makes an edited document " + expected) { @Override protected boolean matchesSafely(TextEdit item) { Document copy = document.copy(); @@ -49,13 +49,18 @@ public void describeMismatchSafely(TextEdit textEdit, Description description) { Document copy = document.copy(); copy.applyEdit(textEdit.getRange(), textEdit.getNewText()); String actual = copy.copyText(); - description.appendText("expected:\n'" + expected + "'\nbut was: \n'" + actual + "'\n"); + description.appendText(String.format(""" + expected: + '%s' + but was: + '%s' + """, expected, actual)); } }; } public static Matcher hasText(Document document, Matcher expected) { - return new CustomTypeSafeMatcher("text in range") { + return new CustomTypeSafeMatcher<>("text in range") { @Override protected boolean matchesSafely(Range item) { CharSequence borrowed = document.borrowRange(item); @@ -78,7 +83,7 @@ public void describeMismatchSafely(Range range, Description description) { } public static Matcher diagnosticWithMessage(Matcher message) { - return new CustomTypeSafeMatcher("has matching message") { + return new CustomTypeSafeMatcher<>("has matching message") { @Override protected boolean matchesSafely(Diagnostic item) { return message.matches(item.getMessage()); diff --git a/src/test/java/software/amazon/smithy/lsp/RequestBuilders.java b/src/test/java/software/amazon/smithy/lsp/RequestBuilders.java index 4181faa..e0f2bc9 100644 --- a/src/test/java/software/amazon/smithy/lsp/RequestBuilders.java +++ b/src/test/java/software/amazon/smithy/lsp/RequestBuilders.java @@ -75,7 +75,7 @@ public static DidChangeWorkspaceFolders didChangeWorkspaceFolders() { public static final class DidChange { private String uri; - private Integer version; + private Integer version = 1; private Range range; private String text; diff --git a/src/test/java/software/amazon/smithy/lsp/SmithyLanguageServerTest.java b/src/test/java/software/amazon/smithy/lsp/SmithyLanguageServerTest.java index 9c84517..22ea340 100644 --- a/src/test/java/software/amazon/smithy/lsp/SmithyLanguageServerTest.java +++ b/src/test/java/software/amazon/smithy/lsp/SmithyLanguageServerTest.java @@ -64,6 +64,7 @@ import software.amazon.smithy.build.model.MavenConfig; import software.amazon.smithy.build.model.SmithyBuildConfig; import software.amazon.smithy.lsp.document.Document; +import software.amazon.smithy.lsp.ext.SelectorParams; import software.amazon.smithy.lsp.project.Project; import software.amazon.smithy.lsp.protocol.LspAdapter; import software.amazon.smithy.lsp.protocol.RangeBuilder; @@ -76,10 +77,12 @@ public class SmithyLanguageServerTest { @Test public void runsSelector() throws Exception { - String model = safeString("$version: \"2\"\n" - + "namespace com.foo\n" - + "\n" - + "string Foo\n"); + String model = safeString(""" + $version: "2" + namespace com.foo + + string Foo + """); TestWorkspace workspace = TestWorkspace.singleModel(model); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -91,15 +94,17 @@ public void runsSelector() throws Exception { @Test public void completion() throws Exception { - String model = safeString("$version: \"2\"\n" + - "namespace com.foo\n" + - "\n" + - "structure Foo {\n" + - " bar: String\n" + - "}\n" + - "\n" + - "@default(0)\n" + - "integer Bar\n"); + String model = safeString(""" + $version: "2" + namespace com.foo + + structure Foo { + bar: String + } + + @default(0) + integer Bar + """); TestWorkspace workspace = TestWorkspace.singleModel(model); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -134,15 +139,19 @@ public void completion() throws Exception { @Test public void completionImports() throws Exception { - String model1 = safeString("$version: \"2\"\n" + - "namespace com.foo\n" + - "\n" + - "structure Foo {\n" + - "}\n"); - String model2 = safeString("$version: \"2\"\n" + - "namespace com.bar\n" + - "\n" + - "string Bar\n"); + String model1 = safeString(""" + $version: "2" + namespace com.foo + + structure Foo { + } + """); + String model2 = safeString(""" + $version: "2" + namespace com.bar + + string Bar + """); TestWorkspace workspace = TestWorkspace.multipleModels(model1, model2); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -179,29 +188,33 @@ public void completionImports() throws Exception { Document document = server.getFirstProject().getDocument(uri); // TODO: The server puts the 'use' on the wrong line - assertThat(completions.get(0).getAdditionalTextEdits(), containsInAnyOrder(makesEditedDocument(document, safeString("$version: \"2\"\n" + - "namespace com.foo\n" + - "use com.bar#Bar\n" + - "\n" + - "structure Foo {\n" + - " bar: Ba\n" + - "}\n")))); + assertThat(completions.get(0).getAdditionalTextEdits(), containsInAnyOrder(makesEditedDocument(document, safeString(""" + $version: "2" + namespace com.foo + use com.bar#Bar + + structure Foo { + bar: Ba + } + """)))); } @Test public void definition() throws Exception { - String model = safeString("$version: \"2\"\n" + - "namespace com.foo\n" + - "\n" + - "@trait\n" + - "string myTrait\n" + - "\n" + - "structure Foo {\n" + - " bar: Baz\n" + - "}\n" + - "\n" + - "@myTrait(\"\")\n" + - "string Baz\n"); + String model = safeString(""" + $version: "2" + namespace com.foo + + @trait + string myTrait + + structure Foo { + bar: Baz + } + + @myTrait("") + string Baz + """); TestWorkspace workspace = TestWorkspace.singleModel(model); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -249,20 +262,22 @@ public void definition() throws Exception { @Test public void hover() throws Exception { - String model = safeString("$version: \"2\"\n" + - "namespace com.foo\n" + - "\n" + - "@trait\n" + - "string myTrait\n" + - "\n" + - "structure Foo {\n" + - " bar: Bar\n" + - "}\n" + - "\n" + - "@myTrait(\"\")\n" + - "structure Bar {\n" + - " baz: String\n" + - "}\n"); + String model = safeString(""" + $version: "2" + namespace com.foo + + @trait + string myTrait + + structure Foo { + bar: Bar + } + + @myTrait("") + structure Bar { + baz: String + } + """); TestWorkspace workspace = TestWorkspace.singleModel(model); SmithyLanguageServer server = initFromWorkspace(workspace); String uri = workspace.getUri("main.smithy"); @@ -296,13 +311,15 @@ public void hover() throws Exception { @Test public void hoverWithBrokenModel() throws Exception { - String model = safeString("$version: \"2\"\n" + - "namespace com.foo\n" + - "\n" + - "structure Foo {\n" + - " bar: Bar\n" + - " baz: String\n" + - "}\n"); + String model = safeString(""" + $version: "2" + namespace com.foo + + structure Foo { + bar: Bar + baz: String + } + """); TestWorkspace workspace = TestWorkspace.singleModel(model); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -321,32 +338,40 @@ public void hoverWithBrokenModel() throws Exception { @Test public void documentSymbol() throws Exception { - String model = safeString("$version: \"2\"\n" + - "namespace com.foo\n" + - "\n" + - "@trait\n" + - "string myTrait\n" + - "\n" + - "structure Foo {\n" + - " @required\n" + - " bar: Bar\n" + - "}\n" + - "\n" + - "structure Bar {\n" + - " @myTrait(\"foo\")\n" + - " baz: Baz\n" + - "}\n" + - "\n" + - "@myTrait(\"abc\")\n" + - "integer Baz\n"); + String model = safeString(""" + $version: "2" + namespace com.foo + + @trait + string myTrait + + structure Foo { + @required + bar: Bar + } + + structure Bar { + @myTrait("foo") + baz: Baz + } + + @myTrait("abc") + integer Baz + """); TestWorkspace workspace = TestWorkspace.singleModel(model); SmithyLanguageServer server = initFromWorkspace(workspace); String uri = workspace.getUri("main.smithy"); + server.didOpen(RequestBuilders.didOpen() + .uri(uri) + .build()); + + server.getLifecycleManager().waitForAllTasks(); + DocumentSymbolParams params = new DocumentSymbolParams(new TextDocumentIdentifier(uri)); List> response = server.documentSymbol(params).get(); - List documentSymbols = response.stream().map(Either::getRight).collect(Collectors.toList()); + List documentSymbols = response.stream().map(Either::getRight).toList(); List names = documentSymbols.stream().map(DocumentSymbol::getName).collect(Collectors.toList()); assertThat(names, hasItem("myTrait")); @@ -359,16 +384,18 @@ public void documentSymbol() throws Exception { @Test public void formatting() throws Exception { - String model = safeString("$version: \"2\"\n" + - "namespace com.foo\n" + - "\n" + - "structure Foo{\n" + - "bar: Baz}\n" + - "\n" + - "@tags(\n" + - "[\"a\",\n" + - " \"b\"])\n" + - "string Baz\n"); + String model = safeString(""" + $version: "2" + namespace com.foo + + structure Foo{ + bar: Baz} + + @tags( + ["a", + "b"]) + string Baz + """); TestWorkspace workspace = TestWorkspace.singleModel(model); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -379,29 +406,33 @@ public void formatting() throws Exception { List edits = server.formatting(params).get(); Document document = server.getFirstProject().getDocument(uri); - assertThat(edits, containsInAnyOrder(makesEditedDocument(document, safeString("$version: \"2\"\n" + - "\n" + - "namespace com.foo\n" + - "\n" + - "structure Foo {\n" + - " bar: Baz\n" + - "}\n" + - "\n" + - "@tags([\"a\", \"b\"])\n" + - "string Baz\n")))); + assertThat(edits, containsInAnyOrder(makesEditedDocument(document, safeString(""" + $version: "2" + + namespace com.foo + + structure Foo { + bar: Baz + } + + @tags(["a", "b"]) + string Baz + """)))); } @Test public void didChange() throws Exception { - String model = safeString("$version: \"2\"\n" + - "\n" + - "namespace com.foo\n" + - "\n" + - "structure GetFooInput {\n" + - "}\n" + - "\n" + - "operation GetFoo {\n" + - "}\n"); + String model = safeString(""" + $version: "2" + + namespace com.foo + + structure GetFooInput { + } + + operation GetFoo { + } + """); TestWorkspace workspace = TestWorkspace.singleModel(model); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -435,16 +466,18 @@ public void didChange() throws Exception { server.getLifecycleManager().waitForAllTasks(); // mostly so you can see what it looks like - assertThat(server.getFirstProject().getDocument(uri).copyText(), equalTo(safeString("$version: \"2\"\n" + - "\n" + - "namespace com.foo\n" + - "\n" + - "structure GetFooInput {\n" + - "}\n" + - "\n" + - "operation GetFoo {\n" + - " input: G\n" + - "}\n"))); + assertThat(server.getFirstProject().getDocument(uri).copyText(), equalTo(safeString(""" + $version: "2" + + namespace com.foo + + structure GetFooInput { + } + + operation GetFoo { + input: G + } + """))); // input: G CompletionParams completionParams = new RequestBuilders.PositionRequest() @@ -458,10 +491,12 @@ public void didChange() throws Exception { @Test public void didChangeReloadsModel() throws Exception { - String model = safeString("$version: \"2\"\n" + - "namespace com.foo\n" + - "\n" + - "operation Foo {}\n"); + String model = safeString(""" + $version: "2" + namespace com.foo + + operation Foo {} + """); TestWorkspace workspace = TestWorkspace.singleModel(model); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -495,14 +530,16 @@ public void didChangeReloadsModel() throws Exception { @Test public void didChangeThenDefinition() throws Exception { - String model = safeString("$version: \"2\"\n" + - "namespace com.foo\n" + - "\n" + - "structure Foo {\n" + - " bar: Bar\n" + - "}\n" + - "\n" + - "string Bar\n"); + String model = safeString(""" + $version: "2" + namespace com.foo + + structure Foo { + bar: Bar + } + + string Bar + """); TestWorkspace workspace = TestWorkspace.singleModel(model); SmithyLanguageServer server = initFromWorkspace(workspace); String uri = workspace.getUri("main.smithy"); @@ -540,16 +577,18 @@ public void didChangeThenDefinition() throws Exception { server.getLifecycleManager().getTask(uri).get(); - assertThat(server.getFirstProject().getDocument(uri).copyText(), equalTo(safeString("$version: \"2\"\n" + - "namespace com.foo\n" + - "\n" + - "structure Foo {\n" + - " bar: Bar\n" + - "}\n" + - "\n" + - "string Baz\n" + - "\n" + - "string Bar\n"))); + assertThat(server.getFirstProject().getDocument(uri).copyText(), equalTo(safeString(""" + $version: "2" + namespace com.foo + + structure Foo { + bar: Bar + } + + string Baz + + string Bar + """))); Location afterChanges = server.definition(definitionParams).get().getLeft().get(0); assertThat(afterChanges.getUri(), equalTo(uri)); @@ -605,12 +644,14 @@ public void definitionWithApply() throws Exception { @Test public void newShapeMixinCompletion() throws Exception { - String model = safeString("$version: \"2\"\n" + - "namespace com.foo\n" + - "\n" + - "@mixin\n" + - "structure Foo {}\n" + - "\n"); + String model = safeString(""" + $version: "2" + namespace com.foo + + @mixin + structure Foo {} + + """); TestWorkspace workspace = TestWorkspace.singleModel(model); SmithyLanguageServer server = initFromWorkspace(workspace); String uri = workspace.getUri("main.smithy"); @@ -650,13 +691,14 @@ public void newShapeMixinCompletion() throws Exception { server.getLifecycleManager().getTask(uri).get(); - assertThat(server.getFirstProject().getDocument(uri).copyText(), equalTo(safeString("$version: \"2\"\n" + - "namespace com.foo\n" + - "\n" + - "@mixin\n" + - "structure Foo {}\n" + - "\n" + - "structure Bar with [F]"))); + assertThat(server.getFirstProject().getDocument(uri).copyText(), equalTo(safeString(""" + $version: "2" + namespace com.foo + + @mixin + structure Foo {} + + structure Bar with [F]"""))); Position currentPosition = range.build().getStart(); CompletionParams completionParams = new RequestBuilders.PositionRequest() @@ -673,13 +715,15 @@ public void newShapeMixinCompletion() throws Exception { @Test public void existingShapeMixinCompletion() throws Exception { - String model = safeString("$version: \"2\"\n" + - "namespace com.foo\n" + - "\n" + - "@mixin\n" + - "structure Foo {}\n" + - "\n" + - "structure Bar {}\n"); + String model = safeString(""" + $version: "2" + namespace com.foo + + @mixin + structure Foo {} + + structure Bar {} + """); TestWorkspace workspace = TestWorkspace.singleModel(model); SmithyLanguageServer server = initFromWorkspace(workspace); String uri = workspace.getUri("main.smithy"); @@ -706,13 +750,15 @@ public void existingShapeMixinCompletion() throws Exception { server.getLifecycleManager().getTask(uri).get(); - assertThat(server.getFirstProject().getDocument(uri).copyText(), equalTo(safeString("$version: \"2\"\n" + - "namespace com.foo\n" + - "\n" + - "@mixin\n" + - "structure Foo {}\n" + - "\n" + - "structure Bar with [F] {}\n"))); + assertThat(server.getFirstProject().getDocument(uri).copyText(), equalTo(safeString(""" + $version: "2" + namespace com.foo + + @mixin + structure Foo {} + + structure Bar with [F] {} + """))); Position currentPosition = range.build().getStart(); CompletionParams completionParams = new RequestBuilders.PositionRequest() @@ -729,12 +775,14 @@ public void existingShapeMixinCompletion() throws Exception { @Test public void diagnosticsOnMemberTarget() { - String model = safeString("$version: \"2\"\n" - + "namespace com.foo\n" - + "\n" - + "structure Foo {\n" - + " bar: Bar\n" - + "}\n"); + String model = safeString(""" + $version: "2" + namespace com.foo + + structure Foo { + bar: Bar + } + """); TestWorkspace workspace = TestWorkspace.singleModel(model); SmithyLanguageServer server = initFromWorkspace(workspace); String uri = workspace.getUri("main.smithy"); @@ -751,13 +799,15 @@ public void diagnosticsOnMemberTarget() { @Test public void diagnosticOnTrait() { - String model = safeString("$version: \"2\"\n" - + "namespace com.foo\n" - + "\n" - + "structure Foo {\n" - + " @bar\n" - + " bar: String\n" - + "}\n"); + String model = safeString(""" + $version: "2" + namespace com.foo + + structure Foo { + @bar + bar: String + } + """); TestWorkspace workspace = TestWorkspace.singleModel(model); SmithyLanguageServer server = initFromWorkspace(workspace); String uri = workspace.getUri("main.smithy"); @@ -779,12 +829,14 @@ public void diagnosticOnTrait() { @Test public void diagnosticsOnShape() throws Exception { - String model = safeString("$version: \"2\"\n" - + "namespace com.foo\n" - + "\n" - + "list Foo {\n" - + " \n" - + "}\n"); + String model = safeString(""" + $version: "2" + namespace com.foo + + list Foo { + \s + } + """); TestWorkspace workspace = TestWorkspace.singleModel(model); StubClient client = new StubClient(); SmithyLanguageServer server = new SmithyLanguageServer(); @@ -823,12 +875,14 @@ public void diagnosticsOnShape() throws Exception { @Test public void insideJar() throws Exception { - String model = safeString("$version: \"2\"\n" - + "namespace com.foo\n" - + "\n" - + "structure Foo {\n" - + " bar: PrimitiveInteger\n" - + "}\n"); + String model = safeString(""" + $version: "2" + namespace com.foo + + structure Foo { + bar: PrimitiveInteger + } + """); TestWorkspace workspace = TestWorkspace.singleModel(model); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -904,9 +958,11 @@ public void addingWatchedFile() throws Exception { public void removingWatchedFile() { TestWorkspace workspace = TestWorkspace.emptyWithDirSource(); String filename = "model/main.smithy"; - String modelText = safeString("$version: \"2\"\n" - + "namespace com.foo\n" - + "string Foo\n"); + String modelText = safeString(""" + $version: "2" + namespace com.foo + string Foo + """); workspace.addModel(filename, modelText); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -932,9 +988,11 @@ public void removingWatchedFile() { public void addingDetachedFile() { TestWorkspace workspace = TestWorkspace.emptyWithDirSource(); String filename = "main.smithy"; - String modelText = safeString("$version: \"2\"\n" - + "namespace com.foo\n" - + "string Foo\n"); + String modelText = safeString(""" + $version: "2" + namespace com.foo + string Foo + """); workspace.addModel(filename, modelText); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -975,9 +1033,11 @@ public void addingDetachedFile() { public void removingAttachedFile() { TestWorkspace workspace = TestWorkspace.emptyWithDirSource(); String filename = "model/main.smithy"; - String modelText = safeString("$version: \"2\"\n" - + "namespace com.foo\n" - + "string Foo\n"); + String modelText = safeString(""" + $version: "2" + namespace com.foo + string Foo + """); workspace.addModel(filename, modelText); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -1022,10 +1082,12 @@ public void loadsProjectWithUnNormalizedSourcesDirs() { .sources(Collections.singletonList("./././smithy")) .build(); String filename = "smithy/main.smithy"; - String modelText = safeString("$version: \"2\"\n" - + "namespace com.foo\n" - + "\n" - + "string Foo\n"); + String modelText = safeString(""" + $version: "2" + namespace com.foo + + string Foo + """); TestWorkspace workspace = TestWorkspace.builder() .withSourceDir(TestWorkspace.dir() .withPath("./smithy") @@ -1048,22 +1110,26 @@ public void loadsProjectWithUnNormalizedSourcesDirs() { @Test public void reloadingProjectWithArrayMetadataValues() throws Exception { - String modelText1 = safeString("$version: \"2\"\n" - + "\n" - + "metadata foo = [1]\n" - + "metadata foo = [2]\n" - + "metadata bar = {a: [1]}\n" - + "\n" - + "namespace com.foo\n" - + "\n" - + "string Foo\n"); - String modelText2 = safeString("$version: \"2\"\n" - + "\n" - + "metadata foo = [3]\n" - + "\n" - + "namespace com.foo\n" - + "\n" - + "string Bar\n"); + String modelText1 = safeString(""" + $version: "2" + + metadata foo = [1] + metadata foo = [2] + metadata bar = {a: [1]} + + namespace com.foo + + string Foo + """); + String modelText2 = safeString(""" + $version: "2" + + metadata foo = [3] + + namespace com.foo + + string Bar + """); TestWorkspace workspace = TestWorkspace.multipleModels(modelText1, modelText2); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -1112,22 +1178,26 @@ public void reloadingProjectWithArrayMetadataValues() throws Exception { @Test public void changingWatchedFilesWithMetadata() throws Exception { - String modelText1 = safeString("$version: \"2\"\n" - + "\n" - + "metadata foo = [1]\n" - + "metadata foo = [2]\n" - + "metadata bar = {a: [1]}\n" - + "\n" - + "namespace com.foo\n" - + "\n" - + "string Foo\n"); - String modelText2 = safeString("$version: \"2\"\n" - + "\n" - + "metadata foo = [3]\n" - + "\n" - + "namespace com.foo\n" - + "\n" - + "string Bar\n"); + String modelText1 = safeString(""" + $version: "2" + + metadata foo = [1] + metadata foo = [2] + metadata bar = {a: [1]} + + namespace com.foo + + string Foo + """); + String modelText2 = safeString(""" + $version: "2" + + metadata foo = [3] + + namespace com.foo + + string Bar + """); TestWorkspace workspace = TestWorkspace.multipleModels(modelText1, modelText2); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -1158,11 +1228,13 @@ public void changingWatchedFilesWithMetadata() throws Exception { public void addingOpenedDetachedFile() throws Exception { TestWorkspace workspace = TestWorkspace.emptyWithDirSource(); String filename = "main.smithy"; - String modelText = safeString("$version: \"2\"\n" - + "\n" - + "namespace com.foo\n" - + "\n" - + "string Foo\n"); + String modelText = safeString(""" + $version: "2" + + namespace com.foo + + string Foo + """); workspace.addModel(filename, modelText); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -1210,9 +1282,11 @@ public void addingOpenedDetachedFile() throws Exception { @Test public void detachingOpenedFile() throws Exception { - String modelText = safeString("$version: \"2\"\n" - + "namespace com.foo\n" - + "string Foo\n"); + String modelText = safeString(""" + $version: "2" + namespace com.foo + string Foo + """); TestWorkspace workspace = TestWorkspace.singleModel(modelText); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -1251,11 +1325,13 @@ public void detachingOpenedFile() throws Exception { public void movingDetachedFile() throws Exception { TestWorkspace workspace = TestWorkspace.emptyWithDirSource(); String filename = "main.smithy"; - String modelText = safeString("$version: \"2\"\n" - + "\n" - + "namespace com.foo\n" - + "\n" - + "string Foo\n"); + String modelText = safeString(""" + $version: "2" + + namespace com.foo + + string Foo + """); workspace.addModel(filename, modelText); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -1294,13 +1370,15 @@ public void updatesDiagnosticsAfterReload() throws Exception { TestWorkspace workspace = TestWorkspace.emptyWithDirSource(); String filename1 = "model/main.smithy"; - String modelText1 = safeString("$version: \"2\"\n" - + "\n" - + "namespace com.foo\n" - + "\n" - + "// using an unknown trait\n" - + "@foo\n" - + "string Bar\n"); + String modelText1 = safeString(""" + $version: "2" + + namespace com.foo + + // using an unknown trait + @foo + string Bar + """); workspace.addModel(filename1, modelText1); StubClient client = new StubClient(); @@ -1322,13 +1400,15 @@ public void updatesDiagnosticsAfterReload() throws Exception { diagnosticWithMessage(containsString("Model.UnresolvedTrait")))); String filename2 = "model/trait.smithy"; - String modelText2 = safeString("$version: \"2\"\n" - + "\n" - + "namespace com.foo\n" - + "\n" - + "// adding the missing trait\n" - + "@trait\n" - + "structure foo {}\n"); + String modelText2 = safeString(""" + $version: "2" + + namespace com.foo + + // adding the missing trait + @trait + structure foo {} + """); workspace.addModel(filename2, modelText2); String uri2 = workspace.getUri(filename2); @@ -1347,9 +1427,11 @@ public void updatesDiagnosticsAfterReload() throws Exception { @Test public void invalidSyntaxModelPartiallyLoads() { - String modelText1 = safeString("$version: \"2\"\n" - + "namespace com.foo\n" - + "string Foo\n"); + String modelText1 = safeString(""" + $version: "2" + namespace com.foo + string Foo + """); String modelText2 = safeString("string Bar\n"); TestWorkspace workspace = TestWorkspace.multipleModels(modelText1, modelText2); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -1388,7 +1470,10 @@ public void invalidSyntaxDetachedProjectBecomesValid() throws Exception { server.didChange(RequestBuilders.didChange() .uri(uri) .range(LspAdapter.origin()) - .text(safeString("$version: \"2\"\nnamespace com.foo\n")) + .text(safeString(""" + $version: "2" + namespace com.foo + """)) .build()); server.getLifecycleManager().waitForAllTasks(); @@ -1460,13 +1545,17 @@ public void addingDetachedFileWithInvalidSyntax() throws Exception { @Test public void appliedTraitsAreMaintainedInPartialLoad() throws Exception { - String modelText1 = safeString("$version: \"2\"\n" - + "namespace com.foo\n" - + "string Foo\n"); - String modelText2 = safeString("$version: \"2\"\n" - + "namespace com.foo\n" - + "string Bar\n" - + "apply Foo @length(min: 1)\n"); + String modelText1 = safeString(""" + $version: "2" + namespace com.foo + string Foo + """); + String modelText2 = safeString(""" + $version: "2" + namespace com.foo + string Bar + apply Foo @length(min: 1) + """); TestWorkspace workspace = TestWorkspace.multipleModels(modelText1, modelText2); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -1547,7 +1636,11 @@ public void brokenBuildFileEventuallyConsistent() throws Exception { server.didChange(RequestBuilders.didChange() .uri(uri) - .text(safeString("$version: \"2\"\nnamespace com.foo\nstring Foo\n")) + .text(safeString(""" + $version: "2" + namespace com.foo + string Foo + """)) .range(LspAdapter.origin()) .build()); server.getLifecycleManager().waitForAllTasks(); @@ -1560,19 +1653,23 @@ public void brokenBuildFileEventuallyConsistent() throws Exception { @Test public void completionHoverDefinitionWithAbsoluteIds() throws Exception { - String modelText1 = safeString("$version: \"2\"\n" - + "namespace com.foo\n" - + "use com.bar#Bar\n" - + "@com.bar#baz\n" - + "structure Foo {\n" - + " bar: com.bar#Bar\n" - + "}\n"); - String modelText2 = safeString("$version: \"2\"\n" - + "namespace com.bar\n" - + "string Bar\n" - + "string Bar2\n" - + "@trait\n" - + "structure baz {}\n"); + String modelText1 = safeString(""" + $version: "2" + namespace com.foo + use com.bar#Bar + @com.bar#baz + structure Foo { + bar: com.bar#Bar + } + """); + String modelText2 = safeString(""" + $version: "2" + namespace com.bar + string Bar + string Bar2 + @trait + structure baz {} + """); TestWorkspace workspace = TestWorkspace.multipleModels(modelText1, modelText2); SmithyLanguageServer server = initFromWorkspace(workspace); @@ -1631,11 +1728,15 @@ public void completionHoverDefinitionWithAbsoluteIds() throws Exception { @Test public void useCompletionDoesntAutoImport() throws Exception { - String modelText1 = safeString("$version: \"2\"\n" - + "namespace com.foo\n"); - String modelText2 = safeString("$version: \"2\"\n" - + "namespace com.bar\n" - + "string Bar\n"); + String modelText1 = safeString(""" + $version: "2" + namespace com.foo + """); + String modelText2 = safeString(""" + $version: "2" + namespace com.bar + string Bar + """); TestWorkspace workspace = TestWorkspace.multipleModels(modelText1, modelText2); SmithyLanguageServer server = initFromWorkspace(workspace); diff --git a/src/test/java/software/amazon/smithy/lsp/SmithyMatchers.java b/src/test/java/software/amazon/smithy/lsp/SmithyMatchers.java index 6145b42..f579623 100644 --- a/src/test/java/software/amazon/smithy/lsp/SmithyMatchers.java +++ b/src/test/java/software/amazon/smithy/lsp/SmithyMatchers.java @@ -24,7 +24,7 @@ public final class SmithyMatchers { private SmithyMatchers() {} public static Matcher> hasValue(Matcher matcher) { - return new CustomTypeSafeMatcher>("A validated result with value " + matcher.toString()) { + return new CustomTypeSafeMatcher<>("A validated result with value " + matcher.toString()) { @Override protected boolean matchesSafely(ValidatedResult item) { return item.getResult().isPresent() && matcher.matches(item.getResult().get()); @@ -42,7 +42,7 @@ public void describeMismatchSafely(ValidatedResult item, Description descript } public static Matcher hasShapeWithId(String id) { - return new CustomTypeSafeMatcher("a model with the shape id `" + id + "`") { + return new CustomTypeSafeMatcher<>("a model with the shape id `" + id + "`") { @Override protected boolean matchesSafely(Model item) { return item.getShape(ShapeId.from(id)).isPresent(); @@ -59,7 +59,7 @@ public void describeMismatchSafely(Model model, Description description) { } public static Matcher eventWithMessage(Matcher message) { - return new CustomTypeSafeMatcher("has matching message") { + return new CustomTypeSafeMatcher<>("has matching message") { @Override protected boolean matchesSafely(ValidationEvent item) { return message.matches(item.getMessage()); diff --git a/src/test/java/software/amazon/smithy/lsp/SmithyVersionRefactoringTest.java b/src/test/java/software/amazon/smithy/lsp/SmithyVersionRefactoringTest.java index 166b82e..f7337b5 100644 --- a/src/test/java/software/amazon/smithy/lsp/SmithyVersionRefactoringTest.java +++ b/src/test/java/software/amazon/smithy/lsp/SmithyVersionRefactoringTest.java @@ -22,6 +22,7 @@ import static org.hamcrest.Matchers.hasKey; import static org.hamcrest.Matchers.hasSize; import static software.amazon.smithy.lsp.SmithyLanguageServerTest.initFromWorkspace; +import static software.amazon.smithy.lsp.document.DocumentTest.safeString; import java.util.List; import java.util.stream.Collectors; @@ -48,8 +49,10 @@ public class SmithyVersionRefactoringTest { @Test public void noVersionDiagnostic() throws Exception { - String model = "namespace com.foo\n" + - "string Foo\n"; + String model = safeString(""" + namespace com.foo + string Foo + """); TestWorkspace workspace = TestWorkspace.singleModel(model); StubClient client = new StubClient(); SmithyLanguageServer server = initFromWorkspace(workspace, client); @@ -70,9 +73,6 @@ public void noVersionDiagnostic() throws Exception { .collect(Collectors.toList()); assertThat(defineVersionDiagnostics, hasSize(1)); - Diagnostic diagnostic = defineVersionDiagnostics.get(0); - assertThat(diagnostic.getRange().getStart(), equalTo(new Position(0, 0))); - assertThat(diagnostic.getRange().getEnd(), equalTo(new Position(0, 17))); CodeActionContext context = new CodeActionContext(diagnostics); context.setTriggerKind(CodeActionTriggerKind.Automatic); CodeActionParams codeActionParams = new CodeActionParams( @@ -88,17 +88,21 @@ public void noVersionDiagnostic() throws Exception { TextEdit edit = edits.get(0); Document document = server.getFirstProject().getDocument(uri); document.applyEdit(edit.getRange(), edit.getNewText()); - assertThat(document.copyText(), equalTo("$version: \"1\"\n" + - "\n" + - "namespace com.foo\n" + - "string Foo\n")); + assertThat(document.copyText(), equalTo(safeString(""" + $version: "1" + + namespace com.foo + string Foo + """))); } @Test public void oldVersionDiagnostic() throws Exception { - String model = "$version: \"1\"\n" + - "namespace com.foo\n" + - "string Foo\n"; + String model = """ + $version: "1" + namespace com.foo + string Foo + """; TestWorkspace workspace = TestWorkspace.singleModel(model); StubClient client = new StubClient(); SmithyLanguageServer server = initFromWorkspace(workspace, client); @@ -137,16 +141,20 @@ public void oldVersionDiagnostic() throws Exception { TextEdit edit = edits.get(0); Document document = server.getFirstProject().getDocument(uri); document.applyEdit(edit.getRange(), edit.getNewText()); - assertThat(document.copyText(), equalTo("$version: \"2\"\n" + - "namespace com.foo\n" + - "string Foo\n")); + assertThat(document.copyText(), equalTo(""" + $version: "2" + namespace com.foo + string Foo + """)); } @Test public void mostRecentVersion() { - String model = "$version: \"2\"\n" + - "namespace com.foo\n" + - "string Foo\n"; + String model = """ + $version: "2" + namespace com.foo + string Foo + """; TestWorkspace workspace = TestWorkspace.singleModel(model); SmithyLanguageServer server = initFromWorkspace(workspace); String uri = workspace.getUri("main.smithy"); diff --git a/src/test/java/software/amazon/smithy/lsp/TestWorkspace.java b/src/test/java/software/amazon/smithy/lsp/TestWorkspace.java index 21d3c40..f95c0fe 100644 --- a/src/test/java/software/amazon/smithy/lsp/TestWorkspace.java +++ b/src/test/java/software/amazon/smithy/lsp/TestWorkspace.java @@ -6,14 +6,12 @@ package software.amazon.smithy.lsp; import java.io.IOException; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.stream.Collectors; import software.amazon.smithy.build.model.SmithyBuildConfig; import software.amazon.smithy.model.node.Node; import software.amazon.smithy.model.node.NodeMapper; @@ -62,7 +60,7 @@ public String getUri(String filename) { */ public void addModel(String relativePath, String model) { try { - Files.write(root.resolve(relativePath), model.getBytes(StandardCharsets.UTF_8)); + Files.writeString(root.resolve(relativePath), model); } catch (IOException e) { throw new RuntimeException(e); } @@ -178,7 +176,7 @@ protected void writeModels(Path toDir) { private static void writeModels(Path toDir, Map models) throws Exception { for (Map.Entry entry : models.entrySet()) { - Files.write(toDir.resolve(entry.getKey()), entry.getValue().getBytes(StandardCharsets.UTF_8)); + Files.writeString(toDir.resolve(entry.getKey()), entry.getValue()); } } } @@ -239,11 +237,11 @@ public TestWorkspace build() { List sources = new ArrayList<>(); sources.addAll(sourceModels.keySet()); - sources.addAll(sourceDirs.stream().map(d -> d.path).collect(Collectors.toList())); + sources.addAll(sourceDirs.stream().map(d -> d.path).toList()); List imports = new ArrayList<>(); imports.addAll(importModels.keySet()); - imports.addAll(importDirs.stream().map(d -> d.path).collect(Collectors.toList())); + imports.addAll(importDirs.stream().map(d -> d.path).toList()); if (config == null) { config = SmithyBuildConfig.builder() @@ -267,7 +265,7 @@ private static void writeConfig(Path root, SmithyBuildConfig config) { String configString = Node.prettyPrintJson(MAPPER.serialize(config)); Path configPath = root.resolve("smithy-build.json"); try { - Files.write(configPath, configString.getBytes(StandardCharsets.UTF_8)); + Files.writeString(configPath, configString); } catch (Exception e) { throw new RuntimeException(e); } diff --git a/src/test/java/software/amazon/smithy/lsp/UtilMatchers.java b/src/test/java/software/amazon/smithy/lsp/UtilMatchers.java index 6c73b42..f4dc110 100644 --- a/src/test/java/software/amazon/smithy/lsp/UtilMatchers.java +++ b/src/test/java/software/amazon/smithy/lsp/UtilMatchers.java @@ -19,7 +19,7 @@ public final class UtilMatchers { private UtilMatchers() {} public static Matcher> anOptionalOf(Matcher matcher) { - return new CustomTypeSafeMatcher>("An optional that is present with value " + matcher.toString()) { + return new CustomTypeSafeMatcher<>("An optional that is present with value " + matcher.toString()) { @Override protected boolean matchesSafely(Optional item) { return item.isPresent() && matcher.matches(item.get()); @@ -27,7 +27,7 @@ protected boolean matchesSafely(Optional item) { @Override public void describeMismatchSafely(Optional item, Description description) { - if (!item.isPresent()) { + if (item.isEmpty()) { description.appendText("was an empty optional"); } else { matcher.describeMismatch(item.get(), description); diff --git a/src/test/java/software/amazon/smithy/lsp/document/DocumentParserTest.java b/src/test/java/software/amazon/smithy/lsp/document/DocumentParserTest.java index cdd1c44..db29102 100644 --- a/src/test/java/software/amazon/smithy/lsp/document/DocumentParserTest.java +++ b/src/test/java/software/amazon/smithy/lsp/document/DocumentParserTest.java @@ -29,11 +29,13 @@ public class DocumentParserTest { @Test public void jumpsToLines() { - String text = "abc\n" + - "def\n" + - "ghi\n" + - "\n" + - "\n"; + String text = """ + abc + def + ghi + + + """; DocumentParser parser = DocumentParser.of(safeString(text)); assertEquals(0, parser.position()); assertEquals(1, parser.line()); @@ -224,31 +226,33 @@ public void getsDocumentVersion() { @Test public void getsDocumentShapes() { - String text = "$version: \"2\"\n" - + "namespace com.foo\n" - + "string Foo\n" - + "structure Bar {\n" - + " bar: Foo\n" - + "}\n" - + "enum Baz {\n" - + " ONE\n" - + " TWO\n" - + "}\n" - + "intEnum Biz {\n" - + " ONE = 1\n" - + "}\n" - + "@mixin\n" - + "structure Boz {\n" - + " elided: String\n" - + "}\n" - + "structure Mixed with [Boz] {\n" - + " $elided\n" - + "}\n" - + "operation Get {\n" - + " input := {\n" - + " a: Integer\n" - + " }\n" - + "}\n"; + String text = """ + $version: "2" + namespace com.foo + string Foo + structure Bar { + bar: Foo + } + enum Baz { + ONE + TWO + } + intEnum Biz { + ONE = 1 + } + @mixin + structure Boz { + elided: String + } + structure Mixed with [Boz] { + $elided + } + operation Get { + input := { + a: Integer + } + } + """; Set shapes = Model.assembler() .addUnparsedModel("main.smithy", text) .assemble() diff --git a/src/test/java/software/amazon/smithy/lsp/document/DocumentTest.java b/src/test/java/software/amazon/smithy/lsp/document/DocumentTest.java index b2da248..b3acf48 100644 --- a/src/test/java/software/amazon/smithy/lsp/document/DocumentTest.java +++ b/src/test/java/software/amazon/smithy/lsp/document/DocumentTest.java @@ -166,9 +166,10 @@ public void appliesInsertionEdit() { document.applyEdit(editRange, editText); - assertThat(document.copyText(), equalTo(safeString("abzx\n" + - "yc\n" + - "def"))); + assertThat(document.copyText(), equalTo(safeString(""" + abzx + yc + def"""))); assertThat(document.indexOfLine(0), equalTo(0)); assertThat(document.indexOfLine(1), equalTo(safeIndex(5, 1))); assertThat(document.indexOfLine(2), equalTo(safeIndex(8, 2))); @@ -198,9 +199,11 @@ public void appliesDeletionEdit() { @Test public void getsIndexOfLine() { - String s = "abc\n" + - "def\n" + - "hij\n"; + String s = """ + abc + def + hij + """; Document document = makeDocument(s); assertThat(document.indexOfLine(0), equalTo(0)); @@ -461,7 +464,6 @@ public static int safeIndex(int standardOffset, int line) { // Makes a string literal with '\n' newline characters use the actual OS line separator. // Don't use this if you didn't manually type out the '\n's. - // TODO: Remove this for textblocks public static String safeString(String s) { return s.replace("\n", System.lineSeparator()); } @@ -471,11 +473,12 @@ private static Document makeDocument(String s) { } public static Matcher string(String other) { - return new CustomTypeSafeMatcher(other) { + return new CustomTypeSafeMatcher<>(other) { @Override protected boolean matchesSafely(CharSequence item) { return other.replace("\n", "\\n").replace("\r", "\\r").equals(item.toString().replace("\n", "\\n").replace("\r", "\\r")); } + @Override public void describeMismatchSafely(CharSequence item, Description description) { String o = other.replace("\n", "\\n").replace("\r", "\\r"); @@ -486,7 +489,7 @@ public void describeMismatchSafely(CharSequence item, Description description) { } public static Matcher documentShapeId(String other, DocumentId.Type type) { - return new CustomTypeSafeMatcher(other + " with type: " + type) { + return new CustomTypeSafeMatcher<>(other + " with type: " + type) { @Override protected boolean matchesSafely(DocumentId item) { return other.equals(item.copyIdValue()) && item.type() == type; diff --git a/src/test/java/software/amazon/smithy/lsp/project/ProjectTest.java b/src/test/java/software/amazon/smithy/lsp/project/ProjectTest.java index d5aad87..21790ba 100644 --- a/src/test/java/software/amazon/smithy/lsp/project/ProjectTest.java +++ b/src/test/java/software/amazon/smithy/lsp/project/ProjectTest.java @@ -263,13 +263,17 @@ public void loadsProjectWithUnNormalizedDirs() { @Test public void changeFileApplyingSimpleTrait() { - String m1 = "$version: \"2\"\n" - + "namespace com.foo\n" - + "string Foo\n" - + "apply Bar @length(min: 1)\n"; - String m2 = "$version: \"2\"\n" - + "namespace com.foo\n" - + "string Bar\n"; + String m1 = """ + $version: "2" + namespace com.foo + string Foo + apply Bar @length(min: 1) + """; + String m2 = """ + $version: "2" + namespace com.foo + string Bar + """; TestWorkspace workspace = TestWorkspace.multipleModels(m1, m2); Project project = ProjectLoader.load(workspace.getRoot()).unwrap(); @@ -290,13 +294,17 @@ public void changeFileApplyingSimpleTrait() { @Test public void changeFileApplyingListTrait() { - String m1 = "$version: \"2\"\n" - + "namespace com.foo\n" - + "string Foo\n" - + "apply Bar @tags([\"foo\"])\n"; - String m2 = "$version: \"2\"\n" - + "namespace com.foo\n" - + "string Bar\n"; + String m1 = """ + $version: "2" + namespace com.foo + string Foo + apply Bar @tags(["foo"]) + """; + String m2 = """ + $version: "2" + namespace com.foo + string Bar + """; TestWorkspace workspace = TestWorkspace.multipleModels(m1, m2); Project project = ProjectLoader.load(workspace.getRoot()).unwrap(); @@ -317,17 +325,23 @@ public void changeFileApplyingListTrait() { @Test public void changeFileApplyingListTraitWithUnrelatedDependencies() { - String m1 = "$version: \"2\"\n" - + "namespace com.foo\n" - + "string Foo\n" - + "apply Bar @tags([\"foo\"])\n"; - String m2 = "$version: \"2\"\n" - + "namespace com.foo\n" - + "string Bar\n" - + "string Baz\n"; - String m3 = "$version: \"2\"\n" - + "namespace com.foo\n" - + "apply Baz @length(min: 1)\n"; + String m1 = """ + $version: "2" + namespace com.foo + string Foo + apply Bar @tags(["foo"]) + """; + String m2 = """ + $version: "2" + namespace com.foo + string Bar + string Baz + """; + String m3 = """ + $version: "2" + namespace com.foo + apply Baz @length(min: 1) + """; TestWorkspace workspace = TestWorkspace.multipleModels(m1, m2, m3); Project project = ProjectLoader.load(workspace.getRoot()).unwrap(); @@ -354,16 +368,22 @@ public void changeFileApplyingListTraitWithUnrelatedDependencies() { @Test public void changingFileApplyingListTraitWithRelatedDependencies() { - String m1 = "$version: \"2\"\n" - + "namespace com.foo\n" - + "string Foo\n" - + "apply Bar @tags([\"foo\"])\n"; - String m2 = "$version: \"2\"\n" - + "namespace com.foo\n" - + "string Bar\n"; - String m3 = "$version: \"2\"\n" - + "namespace com.foo\n" - + "apply Bar @length(min: 1)\n"; + String m1 = """ + $version: "2" + namespace com.foo + string Foo + apply Bar @tags(["foo"]) + """; + String m2 = """ + $version: "2" + namespace com.foo + string Bar + """; + String m3 = """ + $version: "2" + namespace com.foo + apply Bar @length(min: 1) + """; TestWorkspace workspace = TestWorkspace.multipleModels(m1, m2, m3); Project project = ProjectLoader.load(workspace.getRoot()).unwrap(); @@ -388,16 +408,22 @@ public void changingFileApplyingListTraitWithRelatedDependencies() { @Test public void changingFileApplyingListTraitWithRelatedArrayTraitDependencies() { - String m1 = "$version: \"2\"\n" - + "namespace com.foo\n" - + "string Foo\n" - + "apply Bar @tags([\"foo\"])\n"; - String m2 = "$version: \"2\"\n" - + "namespace com.foo\n" - + "string Bar\n"; - String m3 = "$version: \"2\"\n" - + "namespace com.foo\n" - + "apply Bar @tags([\"bar\"])\n"; + String m1 = """ + $version: "2" + namespace com.foo + string Foo + apply Bar @tags(["foo"]) + """; + String m2 = """ + $version: "2" + namespace com.foo + string Bar + """; + String m3 = """ + $version: "2" + namespace com.foo + apply Bar @tags(["bar"]) + """; TestWorkspace workspace = TestWorkspace.multipleModels(m1, m2, m3); Project project = ProjectLoader.load(workspace.getRoot()).unwrap(); @@ -418,13 +444,17 @@ public void changingFileApplyingListTraitWithRelatedArrayTraitDependencies() { @Test public void changingFileWithDependencies() { - String m1 = "$version: \"2\"\n" - + "namespace com.foo\n" - + "string Foo\n"; - String m2 = "$version: \"2\"\n" - + "namespace com.foo\n" - + "string Bar\n" - + "apply Foo @length(min: 1)\n"; + String m1 = """ + $version: "2" + namespace com.foo + string Foo + """; + String m2 = """ + $version: "2" + namespace com.foo + string Bar + apply Foo @length(min: 1) + """; TestWorkspace workspace = TestWorkspace.multipleModels(m1, m2); Project project = ProjectLoader.load(workspace.getRoot()).unwrap(); @@ -445,13 +475,17 @@ public void changingFileWithDependencies() { @Test public void changingFileWithArrayDependencies() { - String m1 = "$version: \"2\"\n" - + "namespace com.foo\n" - + "string Foo\n"; - String m2 = "$version: \"2\"\n" - + "namespace com.foo\n" - + "string Bar\n" - + "apply Foo @tags([\"foo\"])\n"; + String m1 = """ + $version: "2" + namespace com.foo + string Foo + """; + String m2 = """ + $version: "2" + namespace com.foo + string Bar + apply Foo @tags(["foo"]) + """; TestWorkspace workspace = TestWorkspace.multipleModels(m1, m2); Project project = ProjectLoader.load(workspace.getRoot()).unwrap(); @@ -472,14 +506,18 @@ public void changingFileWithArrayDependencies() { @Test public void changingFileWithMixedArrayDependencies() { - String m1 = "$version: \"2\"\n" - + "namespace com.foo\n" - + "@tags([\"foo\"])\n" - + "string Foo\n"; - String m2 = "$version: \"2\"\n" - + "namespace com.foo\n" - + "string Bar\n" - + "apply Foo @tags([\"foo\"])\n"; + String m1 = """ + $version: "2" + namespace com.foo + @tags(["foo"]) + string Foo + """; + String m2 = """ + $version: "2" + namespace com.foo + string Bar + apply Foo @tags(["foo"]) + """; TestWorkspace workspace = TestWorkspace.multipleModels(m1, m2); Project project = ProjectLoader.load(workspace.getRoot()).unwrap(); @@ -500,16 +538,22 @@ public void changingFileWithMixedArrayDependencies() { @Test public void changingFileWithArrayDependenciesWithDependencies() { - String m1 = "$version: \"2\"\n" - + "namespace com.foo\n" - + "string Foo\n"; - String m2 = "$version: \"2\"\n" - + "namespace com.foo\n" - + "string Bar\n" - + "apply Foo @tags([\"foo\"])\n"; - String m3 = "$version: \"2\"\n" - + "namespace com.foo\n" - + "apply Bar @length(min: 1)\n"; + String m1 = """ + $version: "2" + namespace com.foo + string Foo + """; + String m2 = """ + $version: "2" + namespace com.foo + string Bar + apply Foo @tags(["foo"]) + """; + String m3 = """ + $version: "2" + namespace com.foo + apply Bar @length(min: 1) + """; TestWorkspace workspace = TestWorkspace.multipleModels(m1, m2, m3); Project project = ProjectLoader.load(workspace.getRoot()).unwrap(); @@ -547,15 +591,21 @@ public void changingFileWithArrayDependenciesWithDependencies() { @Test public void removingSimpleApply() { - String m1 = "$version: \"2\"\n" - + "namespace com.foo\n" - + "apply Bar @length(min: 1)\n"; - String m2 = "$version: \"2\"\n" - + "namespace com.foo\n" - + "string Bar\n"; - String m3 = "$version: \"2\"\n" - + "namespace com.foo\n" - + "apply Bar @pattern(\"a\")\n"; + String m1 = """ + $version: "2" + namespace com.foo + apply Bar @length(min: 1) + """; + String m2 = """ + $version: "2" + namespace com.foo + string Bar + """; + String m3 = """ + $version: "2" + namespace com.foo + apply Bar @pattern("a") + """; TestWorkspace workspace = TestWorkspace.multipleModels(m1, m2, m3); Project project = ProjectLoader.load(workspace.getRoot()).unwrap(); @@ -579,15 +629,21 @@ public void removingSimpleApply() { @Test public void removingArrayApply() { - String m1 = "$version: \"2\"\n" - + "namespace com.foo\n" - + "apply Bar @tags([\"foo\"])\n"; - String m2 = "$version: \"2\"\n" - + "namespace com.foo\n" - + "string Bar\n"; - String m3 = "$version: \"2\"\n" - + "namespace com.foo\n" - + "apply Bar @tags([\"bar\"])\n"; + String m1 = """ + $version: "2" + namespace com.foo + apply Bar @tags(["foo"]) + """; + String m2 = """ + $version: "2" + namespace com.foo + string Bar + """; + String m3 = """ + $version: "2" + namespace com.foo + apply Bar @tags(["bar"]) + """; TestWorkspace workspace = TestWorkspace.multipleModels(m1, m2, m3); Project project = ProjectLoader.load(workspace.getRoot()).unwrap();