Group @testable imports at the bottom, per public/rules-swift's swiftformat. A
behavior-preserving import-ordering reformat across 252 files (mostly tests).
--trailingclosures was deliberately not adopted (cosmetic, and swiftformat flags
it as caution-worthy).
A selector/field xpath in an identity constraint may name elements/attributes
with namespace-qualified name tests; every prefix used must be a declared
xmlns: prefix in scope (the implicit xml prefix excepted). identityXPathErrors,
after the existing syntax check, now resolves each name-test prefix against the
in-scope bindings (namespaceBindingsInScope, which captures the schema root and
every ancestor) and rejects an undeclared one.
An adversarial review confirmed no false positive: a prefix declared on the
schema root, any intermediate ancestor, or the selector/field element resolves
correctly; xml, the child::/attribute:: axis keywords (colon-free), prefix:*,
and inter-token whitespace are all handled.
XSTS: invalid-schemas-accepted 77 to 75 (idI010, idJ011), valid-schemas-rejected
held at 0, no other bucket moved. (Two existing xpath-syntax fixtures used an
undeclared 'ns' prefix to test name-test syntax; the test schema now declares
xmlns:ns so they exercise syntax with a bound prefix.)
An xs:unique / xs:key / xs:keyref content model is (annotation?, selector,
field+): exactly one selector, then one or more fields, in that order. The
structure walk previously checked only that the children were drawn from
{annotation, selector, field}, not their cardinality or order, so a field
before the selector, a second selector, or a missing field was accepted.
identityConstraintContentErrors enforces it, wired into the per-component
structural dispatch. XSTS: invalid-schemas-accepted 110 to 104 (six caught:
idA044/046, idB044/046, idC047/049), valid-schemas-rejected held at 0, no
other bucket moved.
An identity constraint's selector and field xpath must be in the XSD 1.0
restricted-XPath subset (Part 1, 3.11.6), far narrower than full XPath: a
leading optional .//, then /-separated steps, a step being '.', a name test
(QName, '*', or NCName:*), or a child:: axis; a field path may end in an
attribute step (@x or attribute::x). No predicates, no other axes, no absolute
or interior //. The xpath was stored raw and compiled lazily with try?, so a
malformed one was silently accepted.
It is now lexed into a whitespace-tolerant token stream and parsed against the
grammar: whitespace between tokens is allowed (child :: a, . //.) while // must
be adjacent and a name test's own ':' may not be spaced. The name lexer uses
the XML NameChar set so a non-ASCII NCName is accepted.
The two identity tests that fed a malformed xpath and expected a
validation-time located error now assert the stronger compile-time rejection.
XSTS: invalid schemas accepted 785 to 736, valid schemas rejected held at 72,
instance buckets unchanged.