Skip to content

feat(swift_core): implement SchemaCompiler for AST translation#1736

Draft
pinieb wants to merge 33 commits into
a2ui-project:mainfrom
pinieb:swift-json-schema-compiler
Draft

feat(swift_core): implement SchemaCompiler for AST translation#1736
pinieb wants to merge 33 commits into
a2ui-project:mainfrom
pinieb:swift-json-schema-compiler

Conversation

@pinieb

@pinieb pinieb commented Jun 23, 2026

Copy link
Copy Markdown
Collaborator

Description

  • Fully implement SchemaCompiler to translate JSONValue into SchemaNodes.
  • Add support for boolean schemas (true = always valid, false = always invalid).
  • Implement structural keyword interception ($id, $defs, $dynamicAnchor).
  • Ensure $id properly updates the base URI and resets the JSON pointer scope.
  • Ensure $defs are recursively compiled and cached in the SchemaRegistry
    for synchronous $ref lookup during evaluation.
  • Add comprehensive compiler test coverage for scope resets and definition caching.

Pre-launch Checklist

For this PR:

  • I have added updates to the CHANGELOG.
  • I updated/added relevant documentation.
  • My code changes (if any) have tests.
  • If my branch is on fork, I have verified that scripts/e2e_test.sh passes.
    • Ran run_tests.sh for Swift

If you need help, consider asking for advice on the discussion board.

pinieb and others added 28 commits June 21, 2026 09:20
This change establishes the foundational infrastructure for Swift libraries in the A2UI monorepo. There is just enough code (JSONValue.swift and its tests) to standup a SwiftPM library and get CI up and running.
Every node in a compiled JSON Schema AST must have a deterministic identity to allow for $ref resolution and accurate error reporting. This identity is a combination of a Base URI and a JSON Pointer (RFC 6901).

This change introduces the mechanisms to do this.
…xt management

- Add `ValidationContext` and `ValidatorConfiguration` to safely pass
  execution state (like max depth limits) down the AST without mutation.
- Add `ValidationResult` struct designed to support the 2020-12
  hierarchical output format, tracking errors and annotations.
- Define the `KeywordEvaluator` protocol to standardize keyword execution.
- Implement the `SchemaNode` executable AST struct with logic to aggregate
  results, errors, and annotations from multiple evaluators.
- Add test coverage for recursion depth limits and result aggregation.
…egistry

- Add `SchemaRegistry` as a shared reference type to cache compiled
  `SchemaNode`s, enabling synchronous `$ref` resolution and preventing
  infinite CoW loops during deep evaluation.
- Add `KeywordRegistry` and `EvaluatorFactory` to decouple keyword
  parsing from the core engine, allowing runtime extensibility.
- Stub `SchemaCompiler` to resolve dependency graph for applicators.
- Add test coverage for node caching and custom keyword injection.
- Fully implement `SchemaCompiler` to translate `JSONValue` into `SchemaNode`s.
- Add support for boolean schemas (`true` = always valid, `false` = always invalid).
- Implement structural keyword interception (`$id`, `$defs`, `$dynamicAnchor`).
- Ensure `$id` properly updates the base URI and resets the JSON pointer scope.
- Ensure `$defs` are recursively compiled and cached in the `SchemaRegistry`
  for synchronous `$ref` lookup during evaluation.
- Add comprehensive compiler test coverage for scope resets and definition caching.
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Signed-off-by: Pete Biencourt <pinieb@users.noreply.github.com>
# Conflicts:
#	Package.swift
#	renderers/swift_core/AGENTS.md
#	swift/core/CODING_STANDARDS.md
#	swift/core/JSONSchema/README.md
#	swift/core/JSONSchema/Sources/JSONPointer.swift
#	swift/core/JSONSchema/Sources/JSONValue.swift
#	swift/core/JSONSchema/Sources/KeywordEvaluator.swift
#	swift/core/JSONSchema/Sources/SchemaIdentity.swift
#	swift/core/JSONSchema/Sources/SchemaNode.swift
#	swift/core/JSONSchema/Sources/SchemaRegistry.swift
#	swift/core/JSONSchema/Sources/ValidationContext.swift
#	swift/core/JSONSchema/Sources/ValidationError.swift
#	swift/core/JSONSchema/Sources/ValidationResult.swift
#	swift/core/JSONSchema/Sources/ValidatorConfiguration.swift
#	swift/core/JSONSchema/Tests/ExecutionContractsTests.swift
#	swift/core/JSONSchema/Tests/JSONValueTests.swift
#	swift/core/JSONSchema/Tests/SchemaIdentityTests.swift
#	swift/core/README.md
…gement

# Conflicts:
#	swift/core/JSONSchema/Sources/KeywordRegistry.swift
#	swift/core/JSONSchema/Sources/SchemaCompiler.swift
#	swift/core/JSONSchema/Tests/KeywordRegistryTests.swift
#	swift/core/JSONSchema/Tests/SchemaRegistryTests.swift
…piler

# Conflicts:
#	swift/core/JSONSchema/Sources/SchemaCompilerError.swift
#	swift/core/JSONSchema/Tests/SchemaCompilerTests.swift
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Signed-off-by: Pete Biencourt <pinieb@users.noreply.github.com>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces the A2UISwiftCore package, establishing a generic JSON Schema Draft 2020-12 validator and DSL builder target (JSONSchema) in Swift, complete with unit tests, documentation, and formatting scripts. The review feedback highlights critical improvements needed for full schema specification compliance: SchemaIdentity should support plain string anchors in URI fragments rather than assuming they are always JSONPointers, and compiled schemas must be registered under their anchor-based URIs in the SchemaRegistry to prevent reference resolution failures. Additionally, updatingBaseURI should be updated to correctly handle and split fragments in the new URI to avoid malformed URIs.

Comment on lines +78 to +80
guard let parsedPointer = JSONPointer(stringRepresentation: fragment) else {
return nil
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The SchemaIdentity initializer currently assumes that any URI fragment is a valid JSONPointer. If the fragment is a plain anchor (e.g., #my-anchor), JSONPointer(stringRepresentation:) will return nil, causing the entire SchemaIdentity initialization to fail.\n\nIn JSON Schema Draft 2020-12, plain anchors are valid URI fragments used by $anchor and $dynamicAnchor. To support resolving schemas via anchors, SchemaIdentity should be updated to allow fragments that are either a JSONPointer or a plain string anchor.

Comment on lines +90 to +93
var parsedAnchor: String? = nil
if let anchorVal = dict["$dynamicAnchor"], case .string(let anchorStr) = anchorVal {
parsedAnchor = anchorStr
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

While $dynamicAnchor is parsed here, the compiled SchemaNode is not registered in the SchemaRegistry under its anchor-based URI (e.g., baseURI + \"#\" + anchorStr). Additionally, interception and registration for the standard $anchor keyword are completely missing.\n\nThis is likely a consequence of SchemaIdentity only supporting JSONPointer fragments. Without registering schemas under their anchor URIs, resolving references ($ref or $dynamicRef) that point to anchors (e.g., \"$ref\": \"#my-anchor\") will fail during evaluation.

Comment on lines +102 to +104
public func updatingBaseURI(to newURI: String) -> SchemaIdentity {
return SchemaIdentity(uncheckedBaseURI: newURI, pointer: JSONPointer())
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If newURI contains a fragment, SchemaIdentity(uncheckedBaseURI:pointer:) will not split it, leaving the fragment inside baseURI. This can lead to malformed URIs when subsequent paths are appended (e.g., https://example.com/schema#foo#/properties/bar).\n\nWe can resolve this by attempting to parse newURI using SchemaIdentity(uri:) first, which correctly splits the fragment if present.

  public func updatingBaseURI(to newURI: String) -> SchemaIdentity {
    if let parsed = SchemaIdentity(uri: newURI) {
      return parsed
    }
    return SchemaIdentity(uncheckedBaseURI: newURI, pointer: JSONPointer())
  }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant