Skip to content

Add inline collection declarations for Smithy IDL 2.1#3134

Open
sugmanue wants to merge 31 commits into
smithy-lang:idl-2.1from
sugmanue:sugmanue/idl-2.1/inline-collections
Open

Add inline collection declarations for Smithy IDL 2.1#3134
sugmanue wants to merge 31 commits into
smithy-lang:idl-2.1from
sugmanue:sugmanue/idl-2.1/inline-collections

Conversation

@sugmanue
Copy link
Copy Markdown
Contributor

Summary

This PR introduces inline collection syntax for Smithy IDL 2.1, allowing list and map shapes to be declared directly in member target positions:

$version: "2.1"

structure MyStructure {
    names: [String]
    tags: {String: String}
    nested: {String: [Integer]}
}

This is syntactic sugar: the assembler generates synthetic shapes (_SyntheticListOfString, _SyntheticMapOfStringToString, etc.) that are shared across structurally equivalent usages.

Changes

Core model (smithy-model)

  • Version.java: Refactored to use a bitmask for feature flags. Added INLINE_COLLECTIONS flag for 2.1.
  • Trait.java: Added SerializationMode enum (ALL, AST_ONLY, NONE) and serializationMode() method to control where traits are serialized.
  • SyntheticShapeTrait: New trait in smithy.synthetic#generated namespace. Uses AST_ONLY serialization, persists in JSON AST but not IDL. Registered via TraitService SPI.
  • SyntheticShapeNaming: Utility for generating deterministic synthetic shape names from target types.
  • SyntheticShapeValidator: Critical validator that errors if traits are applied to synthetic shapes, and warns if user shapes use the _Synthetic prefix.
  • IdlModelLoader: Parses [Target] and {Key: Value} in member target positions. Creates synthetic shapes with deduplication. Version-gated to 2.1+. Nesting capped at 3 levels.
  • SmithyIdlModelSerializer: Emits inline syntax for members targeting synthetic shapes. Excludes synthetic shapes from top-level serialization.
  • ModelSerializer: Uses serializationMode() instead of isSynthetic() for trait filtering.

Syntax tree (smithy-syntax)

  • TreeType.java: Added MEMBER_TARGET, INLINE_LIST_TARGET, INLINE_MAP_TARGET tree types.
  • FormatVisitor.java: Formats inline collections as [Target] and {Key: Value}.

Diff tool (smithy-diff)

  • AddedShape/RemovedShape: Suppress events for synthetic shapes.
  • ModifiedTrait: Added SyntheticShapeTrait to IGNORED_TRAITS.

CLI (smithy-cli)

  • MigrateCommand: Updated to emit version "2.1" and skip any 2.x files.

Documentation

  • spec/idl.rst: ABNF grammar update, new "Inline collection declarations" section, version statement note, examples in List/Map/Structure/Union sections.
  • spec/aggregate-types.rst: Inline syntax notes in List and Map sections.
  • spec/model.rst: Member shapes note, Shape ID _Synthetic prefix reservation, trait restriction note.
  • spec/json-ast.rst: New "Synthetic shapes in the JSON AST" section.
  • spec/type-refinement-traits.rst: Note that @sparse cannot apply to synthetics.
  • spec/selectors.rst: Example for selecting synthetic shapes.
  • guides/style-guide.rst: Recommendation to prefer inline for single-use collections.
  • guides/evolving-models.rst: Migration guidance for inline vs explicit.
  • guides/building-codegen/mapping-shapes-to-languages.rst: Synthetic shape naming guidance.
  • guides/building-codegen/using-the-semantic-model.rst: ShapeVisitor note.
  • guides/model-validation-examples.rst: Selector note for excluding synthetics.
  • guides/smithy-build-json.rst: Tip for selecting synthetics in projections.
  • quickstart.rst: Forward-looking tip about inline syntax.
  • designs/inline-collections.md: Design document.

Testing

  • Valid model tests: Basic inline collections, grouping (shared shapes), union members, use-statement resolution, nested collections.
  • Error tests: Version gating (2.0 rejects inline syntax), nesting depth limit (>3 levels).
  • IDL round-trip test: Parse, serialize, compare matches original.
  • JSON AST round-trip test: IDL to JSON to model comparison.
  • Diff tests: Add/remove inline collections, inline to explicit migration, explicit to inline migration, explicit with constraint traits, no-change scenario.

Limitations

  • Inline collections cannot carry shape-level traits (@sparse, @uniqueItems, @length on the collection). Use explicit shape definitions for these.
  • apply statements cannot target synthetic shapes.
  • Nesting is limited to 3 levels.

sugmanue added 30 commits May 14, 2026 19:19
Add a SerializationMode enum to the Trait interface with three modes:
ALL (default), AST_ONLY, and NONE. This replaces the binary isSynthetic
check in serializers with a more granular control that allows traits to
be serialized in the JSON AST but not in the IDL.

Update ModelSerializer and SmithyIdlModelSerializer to use the new
serializationMode() method. Existing behavior is preserved: traits with
isSynthetic()=true default to NONE, all others default to ALL.
Add SyntheticShapeTrait in the smithy.synthetic namespace that marks
assembler-generated shapes from inline collection syntax. It uses the
new AST_ONLY serialization mode so it appears in JSON AST but not IDL.

Add SyntheticShapeNaming utility that generates deterministic names for
inline list and map shapes using the _Synthetic prefix convention.
Validates that synthetic shapes have no user-applied traits (ERROR) and
warns if user-defined shapes use the reserved _Synthetic name prefix.
Registered as a critical validator so it runs early and blocks further
validation on failure.
Parse [Target] as inline list and {Key: Value} as inline map in member
target positions. The parser creates synthetic list/map shapes with the
@Synthetic trait and deterministic names. Nesting is supported up to 3
levels deep. Version-gated to Smithy IDL 2.1+.

smithy-syntax: Add MEMBER_TARGET, INLINE_LIST_TARGET, and
INLINE_MAP_TARGET tree types. Update formatter to render inline syntax.

smithy-model: Add parseMemberTarget dispatch in IdlModelLoader that
handles LBRACKET/LBRACE tokens and creates synthetic shapes.
Track emitted synthetic shape IDs to avoid registering duplicate
definitions when multiple members use the same inline collection
type (e.g., two members both using [String]).
Fix target resolution for synthetic shape members to correctly resolve
prelude shapes (String, Integer, etc.) and use statements. Add
TraitService provider for SyntheticShapeTrait to support JSON AST
deserialization.

Add valid model test (inline-collections.smithy/.json) verifying list,
map, and nested inline collections produce correct synthetic shapes.
Add error test verifying version gating rejects inline syntax in 2.0.
Synthetic shapes are excluded from top-level serialization. When a
member targets a synthetic shape, the serializer emits inline syntax
([Target] or {Key: Value}) instead of the shape ID. Handles nested
inline collections recursively.

Synthetic shapes are filtered separately from inline IO shapes since
they are unrelated concepts with different serialization contexts.

Add IDL round-trip test for inline collections.
Synthetic shapes are assembler-generated implementation details, not
API surface. Filter them from AddedShape and RemovedShape diff
evaluators to avoid noisy events when inline collections are added or
removed.
…ff tests

Prevent the ModifiedTrait evaluator from producing events about the
smithy.synthetic#generated trait, keeping diff output clean of
implementation details.

Add diff test cases covering: adding/removing inline collections,
no-change scenarios, inline-to-explicit migration, explicit-to-inline
migration, and inline-to-explicit with constraint traits.
Update the migrate command to produce version 2.1 instead of 2.0.
Update the skip pattern to match any 2.x version so already-migrated
files are not re-processed. Update all test expected output files.
Test that structurally equivalent inline collections share one synthetic
shape, that inline collections work in union members, that use
statements are resolved correctly, and that nesting beyond 3 levels
produces an error.
Add MemberTarget, InlineListTarget, and InlineMapTarget productions.
ExplicitShapeMember now targets MemberTarget instead of ShapeId
directly, allowing [Target] and {Key: Value} syntax in member
target positions.
Document the [Target] and {Key: Value} syntax, nesting, synthetic
shape naming, grouping, and limitations.
Update quickstart to use inline collection syntax directly, bump
version to 2.1, and add a note explaining the new syntax.
Suppress IgnoredDuplicateDefinition NOTE for synthetic shapes in
LoaderShapeMap so cross-file deduplication is silent.

Add SyntheticShapeNamingTest with 6 unit tests covering name
generation edge cases. Add error test for user shapes using the
reserved _Synthetic prefix.
@sugmanue sugmanue requested a review from a team as a code owner May 16, 2026 01:41
@sugmanue sugmanue requested a review from kstich May 16, 2026 01:41
@sugmanue sugmanue added the no-changelog-needed This PR doesn't require a changelog entry, so the changelog automation tool should not run on it. label May 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

no-changelog-needed This PR doesn't require a changelog entry, so the changelog automation tool should not run on it.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant