Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
6d9c5a6
feat(swift): add native SDK with streaming-safe rendering
Oct 30, 2026
d6b3ec8
fix(swift): unify UI product and expose remote SwiftPM entry point
Oct 30, 2026
f7e4347
docs(swift): make installation guidance suitable for upstream
Oct 30, 2026
8882c29
docs(swift): refer consumers to distribution release versions
Oct 30, 2026
6af0726
fix(swift): unify theme tokens and banner title emphasis
Oct 30, 2026
9bcde5c
refactor(swift): separate view bindings and clarify theme inheritance
Oct 30, 2026
712fef3
fix(swift): expose official prompt preset and cancel owned resource l…
Oct 31, 2026
07fe677
refactor(swift): align theme overrides with upstream tokens
Nov 1, 2026
7547d89
fix(swift): restore normal object-card surfaces
Nov 1, 2026
deea2a3
fix(swift): honor themed emphasis fonts in native components
Nov 2, 2026
94c13f0
fix(swift): add a readable surface to custom map content
Nov 2, 2026
079ae7b
fix(swift): synchronize schema edits and preserve native control state
Nov 2, 2026
a494b3e
fix(swift): make compatibility verification independent of checkout p…
Nov 2, 2026
e3075fc
refactor(swift-ui): retain the standard catalogue and refine native p…
Nov 2, 2026
01e1755
fix(swift-ui): size streamed images from the container layout
Nov 2, 2026
bb55310
fix(swift-ui): align overview card slots with the content edge
Nov 3, 2026
9f2ed39
feat(swift-ui): flow composite card content beside thumbnails
Nov 3, 2026
084e4d9
Revert "feat(swift-ui): flow composite card content beside thumbnails"
Nov 3, 2026
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
47 changes: 47 additions & 0 deletions .github/workflows/build-swift.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name: Build Swift

on:
push:
branches: [main]
paths:
- 'Package.swift'
- 'packages/swift-lang/**'
- 'packages/swift-ui/**'
- 'packages/lang-core/**'
- 'spec/**'
- '.github/workflows/build-swift.yml'
pull_request:
branches: [main]
paths:
- 'Package.swift'
- 'packages/swift-lang/**'
- 'packages/swift-ui/**'
- 'packages/lang-core/**'
- 'spec/**'
- '.github/workflows/build-swift.yml'

permissions:
contents: read

jobs:
test:
runs-on: macos-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- name: Toolchain
run: swift --version
- name: Verify bundled shared core
run: |
npm ci --prefix packages/swift-lang/scripts --ignore-scripts
node packages/swift-lang/scripts/build.mjs
git diff --exit-code -- packages/swift-lang/Sources/OpenUILang/Resources
- name: SDK tests through the distribution manifest
run: swift test
- name: Authoring validator
run: node --test packages/swift-lang/validation/validation.test.mjs
- name: iOS Simulator compile through the distribution manifest
run: >-
swift build --scratch-path "$RUNNER_TEMP/openui-ios"
--triple arm64-apple-ios16.0-simulator
--sdk "$(xcrun --sdk iphonesimulator --show-sdk-path)"
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,8 @@ draft/

# Accidental CLI template checkouts
packages/openui-cli/src/templates/

# Root SwiftPM consumer/development artifacts
/.build/
/.swiftpm/
/Package.resolved
53 changes: 53 additions & 0 deletions Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// swift-tools-version: 6.0
import PackageDescription

// Remote SwiftPM entry point. Targets reuse the monorepo sources and resources;
// packages/swift-lang and packages/swift-ui remain local development entry points.
let package = Package(
name: "openui",
defaultLocalization: "en",
platforms: [.macOS(.v13), .iOS(.v16)],
products: [
.library(name: "OpenUILang", targets: ["OpenUILang"]),
.library(name: "OpenUISwiftUI", targets: ["OpenUISwiftUI"]),
],
dependencies: [
.package(url: "https://github.com/gonzalezreal/swift-markdown-ui", exact: "2.4.1"),
],
targets: [
.target(
name: "COpenUIRegExp",
path: "packages/swift-lang/Sources/COpenUIRegExp",
exclude: ["README.md", "VENDOR.json", "vendor/LICENSE"],
sources: ["Bridge.c", "RegExpEngine.c", "UnicodeEngine.c"],
publicHeadersPath: "include"
),
.target(
name: "OpenUILang",
dependencies: ["COpenUIRegExp"],
path: "packages/swift-lang/Sources/OpenUILang",
resources: [.copy("Resources/lang-core.js"), .copy("Resources/core-manifest.json"), .copy("Resources/THIRD-PARTY-NOTICES.txt")],
swiftSettings: [.swiftLanguageMode(.v5)]
),
.target(
name: "OpenUISwiftUI",
dependencies: ["OpenUILang", .product(name: "MarkdownUI", package: "swift-markdown-ui")],
path: "packages/swift-ui/Sources/OpenUISwiftUI",
resources: [.process("Resources")],
swiftSettings: [.swiftLanguageMode(.v5)]
),
.testTarget(
name: "OpenUILangTests",
dependencies: ["OpenUILang"],
path: "packages/swift-lang/Tests/OpenUILangTests",
resources: [.copy("Fixtures")],
swiftSettings: [.swiftLanguageMode(.v5)]
),
.testTarget(
name: "OpenUISwiftUITests",
dependencies: ["OpenUISwiftUI"],
path: "packages/swift-ui/Tests/OpenUISwiftUITests",
swiftSettings: [.swiftLanguageMode(.v5)]
),
]
)
3 changes: 3 additions & 0 deletions packages/swift-lang/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.build/
.swiftpm/
DerivedData/
118 changes: 118 additions & 0 deletions packages/swift-lang/COMPATIBILITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# Native compatibility contract

The upstream commit and lang-core source tree are pinned in
`Sources/OpenUILang/Resources/core-manifest.json`. The core sources themselves
remain unchanged. `scripts/build.mjs` performs explicit platform adaptation;
this is not a claim that the generated Apple bundle is an unmodified core.

`scripts/adaptations.json` is the maintained inventory. Each item identifies its
category, location, reason, observable effect, verification and removal condition.
The build embeds the complete inventory, including readiness injection, in the
manifest and hashes the adapter inputs and standalone serializer patch.
The two public modules and the official DSL/schema/action wire vocabulary stay
unchanged. Platform budgets are explicit exceptions to stock-core equivalence.

## Authoring and compatible schema edits

Prefer `Library.extend(...)` followed by `toSchema()` for structural authoring.
Compiled schema projections remain mutable for source compatibility. Their
setters synchronize the retained full ordered JSON Schema, rather than dropping
it or merely clearing a prepared-library cache. Unmodified shared definitions,
references, annotations and constraints stay intact. Binding metadata remains
native. A copy owns its edits and its newly prepared library independently.

Component removal updates component membership; an unregistered `$defs` entry
may remain as a shared data reference. Reordering parameters changes only their
positional property order. Built-in language definitions remain upstream-owned.
This compatibility path adds no competing schema compiler or authoring rules.

## Reproducible checks

Install only the pinned development dependencies with `npm ci --ignore-scripts`
in `scripts`, then run from the SDK root:

```sh
node packages/swift-lang/scripts/build.mjs
node packages/swift-lang/scripts/verify-compatibility.mjs
swift test
```

The verifier builds the pinned official core without Swift patches or readiness
plugins. Upstream telemetry source is retained and its opt-in remains disabled.
It compares every protocol field and ordering in the selected batch, truncated
and intermediate streaming results, complete and replacement results. It does
not discard errors, sort unresolved names or rewrite expected diagnostics.
Only the explicitly named native source-metadata Symbols are omitted; WeakMap
metadata never appears in protocol values.

The checked-in strict fixture is generated with `--write` only after reviewing
an upstream/contract change. Swift tests compare actual parser-facade snapshots
and every typed diagnostic against this independent fixture. Five native action
traces compare events, state and controlled tool calls with the exact pinned
official framework callback, executed with injected host dependencies. It is
the real callback source, not a second handwritten reference interpreter.
Success, failure and cancellation are distinct cases.

The Node verifier also compares four controlled query snapshots, including
disposal with a late result, between official and bundled core managers.
Swift QueryLifecycleTests independently cover native callback replacement and
disposal. This does not claim a live-network, mounted React-versus-SwiftUI test.

Six serializer regressions are kept separate from byte-for-byte equivalence:
the corrected output must parse on the unmodified official parser and preserve
computed meaning. The independent local patch in `scripts/patches` must apply
and produce exactly the build transformation. No upstream submission is implied.

## Readiness and diagnostics

Readiness still injects hooks into lexer, expressions, parser, materializer,
evaluator and evaluate-tree. The pinned upstream API does not expose equivalent
source/dependency provenance. Parser-owned Symbols and evaluated-value WeakMaps
remain side channels; they do not add protocol fields, persisted state or action
parameters. UI regressions verify complete controls can execute while unrelated
text streams, incomplete actions remain blocked, and replacement invalidates old
callbacks. Source injection is deliberately retained until an equivalent API is
verified; moving files would not remove that coupling.

Some official diagnostics omit `source`. The native API's existing nonoptional
`source` property retains its parser display fallback for source compatibility.
The additive `protocolSource` property preserves actual source presence, and
strict raw/typed tests verify the omission rather than inventing a wire field.
No diagnostic code or DSL construct is added.

## Resource limits and verification boundary

- Source: 128 nested delimiter levels or 256 operators per expression. Exceeding
these reports the existing `parse-exception` diagnostic.
- Materialization: 256 recursive levels / 100000 nodes; exhaustion reports the
existing `parse-exception`. Limit tests are separate from equivalence fixtures.
- Ordered JSON decoding: 128 levels, with a native JSON error on exhaustion.
- Pattern execution: 65536 UTF16 pattern units, 1048576 input units, bounded
memory, stack and VM interruptions. Exhaustion blocks form submission with
`Validation could not complete: regular expression resource limit exceeded.`
Ordinary mismatch remains `Invalid format`; invalid pattern keeps official
lenient behavior. The public DSL error vocabulary is not expanded.
- Native value conversion retains a defensive 256-level decoding guard. Values
needing deeper transport remain explicitly outside this verified domain;
their conversion behavior is recorded as unproven in the inventory. This
patch does not claim arbitrary-depth transport or a universal execution budget.

Within these bounds, all maintained reference and strict trace cases must pass.
Passing finite fixtures is regression evidence, not a proof about every program,
future core release, backend, device or network schedule. New differences must
be explained or repaired before changing a checked-in expectation.

## Native controls

EditableTable commits through the component context using the same revision,
readiness and activation gates as standard controls. Its local delivery receipt
is independent of the returned event list and does not acknowledge remote
persistence. Store publication cannot commit a rejected local draft; replacement
starts a new draft lifetime. Tests cover the coordinator and a mounted native
view's real source observation.

Slider's lattice uses the precision of minimum and step for both choices and
dragging. Fractional-origin rounding is an explicit repair of an upstream UI
defect. On non-divisible ranges, the dragged value may clamp to the maximum;
the discrete list includes complete steps. Continuous text input still accepts
off-step numeric drafts and validates their range, as in the reference wrapper.
26 changes: 26 additions & 0 deletions packages/swift-lang/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// swift-tools-version: 6.0
import PackageDescription

let package = Package(
name: "swift-lang",
platforms: [.macOS(.v13), .iOS(.v16)],
products: [
.library(name: "OpenUILang", targets: ["OpenUILang"])
],
targets: [
.target(name: "COpenUIRegExp", exclude: ["README.md", "VENDOR.json", "vendor/LICENSE"],
sources: ["Bridge.c", "RegExpEngine.c", "UnicodeEngine.c"], publicHeadersPath: "include"),
.target(
name: "OpenUILang",
dependencies: ["COpenUIRegExp"],
resources: [.copy("Resources/lang-core.js"), .copy("Resources/core-manifest.json"), .copy("Resources/THIRD-PARTY-NOTICES.txt")],
swiftSettings: [.swiftLanguageMode(.v5)]
),
.testTarget(
name: "OpenUILangTests",
dependencies: ["OpenUILang"],
resources: [.copy("Fixtures")],
swiftSettings: [.swiftLanguageMode(.v5)]
),
]
)
81 changes: 81 additions & 0 deletions packages/swift-lang/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
# swift-lang

Apple-platform bindings for the shared OpenUI `lang-core`. The SwiftPM product and
import are `OpenUILang`; the nested development package identity is `swift-lang`. Swift 6 tools build
in Swift 5 language mode on iOS 16+ and macOS 13+. JavaScriptCore is required.

Parsing, streaming completion, expression evaluation, library extension, Schema,
Prompt generation, Store, query lifecycle and message handling delegate to the
pinned shared core. Native code supplies typed values, lossless UTF-16 transport,
async tools, cancellation and host action execution. There is no Linux fallback.

## Installation

The repository-root `Package.swift` exposes `OpenUILang` and `OpenUISwiftUI` for
remote SwiftPM dependencies. A language-only consumer selects `OpenUILang` from
the `openui` package; a native UI consumer selects `OpenUISwiftUI`, which depends
on this module automatically. See the [Swift installation instructions](../swift-ui/README.md#installation)
for local development and release availability.

The manifest in this directory remains a local development entry point. Do not
add it and the root package to the same application dependency graph.

## Use an exported library

```swift
import OpenUILang

let spec = try LibrarySpec(jsonString: exportedLibrary)
let parser = createParser(schema: compileLibrarySchema(spec))
let result = parser.parse(program)
```

`createParser` returns the `Parser` interface; `createStreamingParser` returns
`StreamParser`. Completion and append/replacement behavior use the shared parser.
`OpenUIString`, `OpenUIArray` and `OpenUIObject` retain JavaScript string and
reference semantics across the native boundary. Concrete JavaScriptCore parser
and Store implementations are internal. `createStore()` returns the core-aligned
`Store` interface, including `getSnapshot`, `subscribe` and `dispose`.

`ParsedMessage` uses the official `content`, `context`, `attributes` and `end`
fields. `context` is parsed JSON or raw text, represented as `JSONValue`; it is
`.null` when absent. `buildMessage` accepts those same fields. The host can retain
its original input separately when exact source bytes are needed.

## Authoring and schema

`DefinedComponent`, `DefinedFunction` and `DefinedAction` follow the core authoring
names. Validation exposes `ParsedRule(type:arg:)` and `ValidatorFn`; `Library.toJSONSchema()`
exports the core schema. Swift definitions and callbacks enter core `defineComponent`, `defineFunction`,
`defineAction`, `createLibrary` and `library.extend` through JSON/Zod transport.
Component reference identity and bindable metadata are preserved. `LibrarySpec`
and signatures come from core `toSpec()`; the adapter does not reproduce an older
Swift schema spelling or custom signature format. JSON Schema integer ranges are
preserved when the Zod importer would otherwise add safe-integer bounds.

## Build and test

```sh
swift test --package-path packages/swift-lang
npm ci --prefix packages/swift-lang/scripts --ignore-scripts
node packages/swift-lang/scripts/build.mjs
```

Ordinary SwiftPM consumers use the checked-in resource without Node or downloads.
The fixed upstream is `f08a660535e55b5b2a24a0eb68568edaf9e4fe4b`, core tree
`bf6be546007f96c87689c7b47c29e1f09175f6f6`. Exact dependency, source and resource
hashes live in `Sources/OpenUILang/Resources/core-manifest.json`.

Compatibility adaptations remain explicit: serializer round-trip grouping and
keys, materialization limits, bounded ECMAScript pattern execution, and native
readiness source injection. The complete inventory, reasons and removal gates
are embedded in the manifest. See [the compatibility contract](COMPATIBILITY.md)
for strict oracle checks, native projection rules and resource exceptions. Raw message-context and
legacy output-format compatibility have been removed. Upstream core source is
unmodified; a source upgrade must revalidate the build corrections and reference
fixtures. Third-party licenses ship with the bundle and bounded regex backend.

A serialized JavaScript realm owns separate parser/Store/query objects. Host
async transport does not hold the realm lock across `await`. Cancellation and
source epochs prevent late responses from updating replacement programs. Typed
native ActionPlans execute at the framework boundary, matching other adapters.
Loading