Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[0.10] Remove deprecated model loading #267

Merged
merged 1 commit into from
Jan 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public void copiesModelFromJarWithSourceProjection() {
assertThat(manifestString, not(containsString("jar-import/d.json")));
assertThat(manifest.getFileString("jar-import/a.smithy").get(), containsString("string A"));
assertThat(manifest.getFileString("jar-import/b/b.smithy").get(), containsString("string B"));
assertThat(manifest.getFileString("jar-import/b/c/c.json").get(), containsString("\"C\""));
assertThat(manifest.getFileString("jar-import/b/c/c.json").get(), containsString("\"foo.baz#C\""));
}

@Test
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ enum AstModelLoader {
private static final Set<String> SERVICE_PROPERTIES = SetUtils.of(
TYPE, "version", "operations", "resources", TRAITS);

void load(ObjectNode model, StringNode version, LoaderVisitor visitor) {
void load(ObjectNode model, LoaderVisitor visitor) {
model.expectNoAdditionalProperties(TOP_LEVEL_PROPERTIES);
visitor.onOpenFile(model.getSourceLocation().getFilename());
loadMetadata(model, visitor);
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
Expand All @@ -50,6 +51,7 @@
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import software.amazon.smithy.model.SourceLocation;
import software.amazon.smithy.model.node.ArrayNode;
import software.amazon.smithy.model.node.BooleanNode;
Expand Down Expand Up @@ -96,6 +98,25 @@

final class IdlModelLoader {

private static final String PUT_KEY = "put";
private static final String CREATE_KEY = "create";
private static final String READ_KEY = "read";
private static final String UPDATE_KEY = "update";
private static final String DELETE_KEY = "delete";
private static final String LIST_KEY = "list";
private static final String RESOURCES_KEY = "resources";
private static final String OPERATIONS_KEY = "operations";
private static final String COLLECTION_OPERATIONS_KEY = "collectionOperations";
private static final String IDENTIFIERS_KEY = "identifiers";
private static final String VERSION_KEY = "version";
private static final String TYPE_KEY = "type";

static final Collection<String> RESOURCE_PROPERTY_NAMES = ListUtils.of(
TYPE_KEY, CREATE_KEY, READ_KEY, UPDATE_KEY, DELETE_KEY, LIST_KEY,
IDENTIFIERS_KEY, RESOURCES_KEY, OPERATIONS_KEY, PUT_KEY, COLLECTION_OPERATIONS_KEY);
static final List<String> SERVICE_PROPERTY_NAMES = ListUtils.of(
TYPE_KEY, VERSION_KEY, OPERATIONS_KEY, RESOURCES_KEY);

// Top-level statements
private static final Set<String> STATEMENTS = SetUtils.of(
"namespace", "use", "service", "operation", "resource", "structure", "union",
Expand All @@ -119,7 +140,6 @@ final class IdlModelLoader {
private final SmithyModelLexer lexer;
private final LoaderVisitor visitor;
private final List<Pair<String, Node>> pendingTraits = new ArrayList<>();
private final Set<VersionFeature> features = new HashSet<>();

private Token current;
private DocComment pendingDocComment;
Expand Down Expand Up @@ -148,64 +168,6 @@ private IdlModelLoader(String filename, SmithyModelLexer lexer, LoaderVisitor vi
}
}

enum VersionFeature {
ALLOW_USE_BEFORE_NAMESPACE {
@Override
void validate(IdlModelLoader loader) {
if (loader.namespace == null && !loader.features.contains(this)) {
raise(loader, "Use statements must appear after a namespace is defined");
}
}
},

ALLOW_MULTIPLE_NAMESPACES {
@Override
void validate(IdlModelLoader loader) {
if (loader.namespace != null && !loader.features.contains(this)) {
raise(loader, format(
"Only a single namespace can be declared per/file. The previous namespace was "
+ "set to `%s`.", loader.namespace));
}
}
},

ALLOW_METADATA_AFTER_NAMESPACE {
@Override
void validate(IdlModelLoader loader) {
if (loader.namespace != null && !loader.features.contains(this)) {
raise(loader, "Metadata statements must appear before a namespace statement");
}
}
},

ALLOW_MULTIPLE_VERSIONS {
@Override
void validate(IdlModelLoader loader) {
if (loader.definedVersion != null && !loader.features.contains(this)) {
raise(loader, "Cannot define multiple versions in the same file");
}
}
};

abstract void validate(IdlModelLoader loader);

// Halts parsing if a version has been explicitly set, otherwise
// adds a WARNING event.
void raise(IdlModelLoader loader, String message) {
if (loader.definedVersion != null) {
throw loader.syntax(message);
}

loader.visitor.onError(ValidationEvent.builder()
.eventId(Validator.MODEL_ERROR)
.severity(Severity.WARNING)
.sourceLocation(loader.current)
.message("Detected deprecated IDL features that will break in future versions "
+ "of Smithy: " + message)
.build());
}
}

private enum TraitValueType { SHAPE, MEMBER, APPLY }

/**
Expand Down Expand Up @@ -312,7 +274,11 @@ private void parseStatement(Token token) {
}

private void parseNamespace() {
VersionFeature.ALLOW_MULTIPLE_NAMESPACES.validate(this);
if (namespace != null) {
throw syntax("Only a single namespace can be declared per/file. The previous namespace was set to "
+ "`" + namespace + "`.");
}

String parsedNamespace = expect(UNQUOTED).lexeme;

if (!ShapeId.isValidNamespace(parsedNamespace)) {
Expand All @@ -324,7 +290,9 @@ private void parseNamespace() {
}

private void parseUseStatement() {
VersionFeature.ALLOW_USE_BEFORE_NAMESPACE.validate(this);
if (namespace == null) {
throw syntax("Use statements must appear after a namespace is defined");
}

if (definedShapes) {
throw syntax("A use statement must come before any shape definition");
Expand Down Expand Up @@ -367,25 +335,23 @@ private void onVersion(Node value) {
}

String parsedVersion = value.expectStringNode().getValue();
VersionFeature.ALLOW_MULTIPLE_VERSIONS.validate(this);

if (definedVersion != null) {
throw syntax("Cannot define multiple versions in the same file");
}

if (!SmithyVersion.isSupported(parsedVersion)) {
throw syntax(format("Invalid Smithy version number: %s", parsedVersion));
}

definedVersion = parsedVersion;

// Enable old Smithy 0.4.0 features that were removed in 0.5.0.
if (definedVersion.equals(SmithyVersion.VERSION_0_4_0.value)) {
features.add(VersionFeature.ALLOW_USE_BEFORE_NAMESPACE);
features.add(VersionFeature.ALLOW_MULTIPLE_NAMESPACES);
features.add(VersionFeature.ALLOW_METADATA_AFTER_NAMESPACE);
features.add(VersionFeature.ALLOW_MULTIPLE_VERSIONS);
}
}

private void parseMetadata() {
VersionFeature.ALLOW_METADATA_AFTER_NAMESPACE.validate(this);
if (namespace != null) {
throw syntax("Metadata statements must appear before a namespace statement");
}

definedMetadata = true;

// metadata key = value\n
Expand Down Expand Up @@ -822,20 +788,55 @@ private void parseService() {
.source(sourceLocation);

ObjectNode shapeNode = parseObjectNode(expect(LBRACE).getSourceLocation(), RBRACE);
shapeNode.warnIfAdditionalProperties(LoaderUtils.SERVICE_PROPERTY_NAMES);
LoaderUtils.loadServiceObject(builder, shapeId, shapeNode);
shapeNode.warnIfAdditionalProperties(SERVICE_PROPERTY_NAMES);
builder.version(shapeNode.expectStringMember(VERSION_KEY).getValue());
optionalIdList(shapeNode, shapeId.getNamespace(), OPERATIONS_KEY).forEach(builder::addOperation);
optionalIdList(shapeNode, shapeId.getNamespace(), RESOURCES_KEY).forEach(builder::addResource);
visitor.onShape(builder);
expectNewline();
}

static Optional<ShapeId> optionalId(ObjectNode node, String namespace, String name) {
return node.getStringMember(name).map(stringNode -> stringNode.expectShapeId(namespace));
}

static List<ShapeId> optionalIdList(ObjectNode node, String namespace, String name) {
return node.getArrayMember(name)
.map(array -> array.getElements().stream()
.map(Node::expectStringNode)
.map(s -> s.expectShapeId(namespace))
.collect(Collectors.toList()))
.orElseGet(Collections::emptyList);
}

private void parseResource() {
SourceLocation sourceLocation = currentLocation();
ShapeId shapeId = parseShapeName();
ResourceShape.Builder builder = ResourceShape.builder().id(shapeId).source(sourceLocation);
visitor.onShape(builder);
ObjectNode shapeNode = parseObjectNode(expect(LBRACE).getSourceLocation(), RBRACE);
shapeNode.warnIfAdditionalProperties(LoaderUtils.RESOURCE_PROPERTY_NAMES);
LoaderUtils.loadResourceObject(builder, shapeId, shapeNode, visitor);

shapeNode.warnIfAdditionalProperties(RESOURCE_PROPERTY_NAMES);
optionalId(shapeNode, shapeId.getNamespace(), PUT_KEY).ifPresent(builder::put);
optionalId(shapeNode, shapeId.getNamespace(), CREATE_KEY).ifPresent(builder::create);
optionalId(shapeNode, shapeId.getNamespace(), READ_KEY).ifPresent(builder::read);
optionalId(shapeNode, shapeId.getNamespace(), UPDATE_KEY).ifPresent(builder::update);
optionalId(shapeNode, shapeId.getNamespace(), DELETE_KEY).ifPresent(builder::delete);
optionalId(shapeNode, shapeId.getNamespace(), LIST_KEY).ifPresent(builder::list);
optionalIdList(shapeNode, shapeId.getNamespace(), OPERATIONS_KEY).forEach(builder::addOperation);
optionalIdList(shapeNode, shapeId.getNamespace(), RESOURCES_KEY).forEach(builder::addResource);
optionalIdList(shapeNode, shapeId.getNamespace(), COLLECTION_OPERATIONS_KEY)
.forEach(builder::addCollectionOperation);

// Load identifiers and resolve forward references.
shapeNode.getObjectMember(IDENTIFIERS_KEY).ifPresent(ids -> {
for (Map.Entry<StringNode, Node> entry : ids.getMembers().entrySet()) {
String name = entry.getKey().getValue();
StringNode target = entry.getValue().expectStringNode();
visitor.onShapeTarget(target.getValue(), target, id -> builder.addIdentifier(name, id));
}
});

expectNewline();
}

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -220,14 +220,21 @@ public void onNamespace(String namespace, FromSourceLocation source) {
*/
public void onShapeTarget(String target, FromSourceLocation sourceLocation, Consumer<ShapeId> resolver) {
try {
ShapeId expectedId = ShapeId.fromOptionalNamespace(namespace, target);
if (namespace.equals(Prelude.NAMESPACE) || hasDefinedShape(expectedId) || target.contains("#")) {
// Account for aliased shapes.
if (useShapes.containsKey(target)) {
resolver.accept(useShapes.get(target));
return;
}

// A namespace is not set when parsing metadata.
ShapeId expectedId = namespace == null
? ShapeId.from(target)
: ShapeId.fromOptionalNamespace(namespace, target);

if (Objects.equals(namespace, Prelude.NAMESPACE) || hasDefinedShape(expectedId) || target.contains("#")) {
// Account for previously seen shapes in this namespace, absolute shapes, and prelude namespaces
// always resolve to prelude shapes.
resolver.accept(expectedId);
} else if (useShapes.containsKey(target)) {
// Account for aliased shapes.
resolver.accept(useShapes.get(target));
} else {
forwardReferenceResolvers.add(new ForwardReferenceResolver(expectedId, resolver));
}
Expand Down
Loading