fix(regex): reject a malformed \p{...} property name in a pattern facet (#145)
A \p{...}/\P{...} property name that can be no XSD charProp under any
repertoire (empty, the bare prefix Is, a non-block name carrying a non-letter,
or Is followed by a non-block character) is now a schema-validity error,
distinct from a well-formed but unrecognised category or block name, which
stays a lenient engine limitation.
XSTS invalid-schemas-accepted 203 to 200, no other bucket moved.
This commit is contained in:
parent
7e30526b2c
commit
947278bb56
@ -22,6 +22,8 @@ Second pre-release. Continues the W3C XSTS schema-validity campaign: **invalid-s
|
||||
|
||||
### Fixed
|
||||
|
||||
- XSTS invalid-schemas-accepted (#145): a `pattern` facet whose `\p{...}` or `\P{...}` property name can be no XSD `charProp` (`IsCategory | IsBlock`) under any repertoire is now rejected as a schema-validity error: an empty name, the bare prefix `Is`, a non-block name carrying a non-letter (`\p{\L}`), or `Is` followed by a non-block character. A well-formed but unrecognised category or block name (such as an unknown `Is`-block) stays a lenient engine limitation rather than an error, so only the unambiguously malformed forms reject. Caught three invalid schemas: invalid-schemas-accepted 203 → 200, no other bucket moved.
|
||||
|
||||
- XSTS invalid-schemas-accepted (#145): two attribute-declaration validity rules. An attribute `ref` may not also carry `form` (the form comes from the referenced global declaration; `src-attribute.3.2`), and no attribute declaration may be named `xmlns` (that name is reserved for namespace declarations; no-xmlns). Caught four invalid schemas: invalid-schemas-accepted 207 → 203, no other bucket moved.
|
||||
|
||||
- XSTS invalid-schemas-accepted (#145): a referencing `attributeGroup` (one carrying a `ref`) is held to its `(annotation?)` content model. It names a definition elsewhere, so it may not itself declare attributes, nested attributeGroup references, or an `anyAttribute`; only a defining `attributeGroup` (with `name`) carries those (`attgD`). Caught three invalid schemas: invalid-schemas-accepted 210 → 207, no other bucket moved.
|
||||
|
||||
@ -133,11 +133,28 @@ extension PureXML.Regex {
|
||||
guard peek() == "}" else { throw RegexError.badClass }
|
||||
advance()
|
||||
guard let predicate = CategoryPredicate(name: name, negated: negated) else {
|
||||
throw RegexError.unsupported("\\p{\(name)}")
|
||||
// An unknown name is by default a limit of this engine, not an error
|
||||
// (stay lenient). But a name that can be NO XSD charProp at all is
|
||||
// unambiguously invalid and rejects, independent of which categories
|
||||
// or blocks this engine happens to recognise.
|
||||
throw Self.isMalformedProperty(name) ? RegexError.invalidProperty : RegexError.unsupported("\\p{\(name)}")
|
||||
}
|
||||
return predicate
|
||||
}
|
||||
|
||||
/// Whether `name` can be no XSD `charProp` (`IsCategory | IsBlock`) under any
|
||||
/// repertoire: empty, the bare `Is` prefix, a non-block name (no `Is` prefix)
|
||||
/// carrying a non-letter, or `Is` followed by a non-`[A-Za-z0-9-]` character.
|
||||
/// A well-formed but unrecognised name (an unknown block such as `IsaA0-a9`)
|
||||
/// is NOT malformed and stays a lenient `unsupported` limit.
|
||||
private static func isMalformedProperty(_ name: String) -> Bool {
|
||||
if name.isEmpty || name == "Is" { return true }
|
||||
guard name.hasPrefix("Is") else {
|
||||
return name.contains { !$0.isLetter }
|
||||
}
|
||||
return name.dropFirst(2).contains { !($0.isLetter || $0.isNumber || $0 == "-") }
|
||||
}
|
||||
|
||||
private func classFrom(_ member: ClassMember) -> CharClass {
|
||||
switch member {
|
||||
case let .scalar(value): .single(value)
|
||||
|
||||
@ -20,6 +20,12 @@ extension PureXML.Regex {
|
||||
/// A character class opened with `[` that the expression ends before
|
||||
/// closing with `]` (`a[`, `[a[:xyz:`). Unambiguously invalid.
|
||||
case unterminatedClass
|
||||
/// The `{...}` of a `\p`/`\P` escape whose content can be no XSD charProp:
|
||||
/// empty, the bare prefix `Is`, a non-block name carrying a character that
|
||||
/// is not a letter, or `Is` followed by a non-block-name character
|
||||
/// (`\p{\L}`, `\p{Is}`). Unambiguously invalid, distinct from an unknown but
|
||||
/// well-formed category or block name (which stays an `unsupported` limit).
|
||||
case invalidProperty
|
||||
|
||||
var description: String {
|
||||
switch self {
|
||||
@ -34,6 +40,7 @@ extension PureXML.Regex {
|
||||
case .reversedQuantifier: "quantifier minimum exceeds maximum"
|
||||
case .incompleteEscape: "an escape '\\' has no following character"
|
||||
case .unterminatedClass: "a character class is not closed with ']'"
|
||||
case .invalidProperty: "a \\p{...} property name is malformed"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -80,7 +80,7 @@ extension PureXML.Schema {
|
||||
private static func rejectsPattern(_ error: PureXML.Regex.RegexError) -> Bool {
|
||||
switch error {
|
||||
case .unbalanced, .danglingQuantifier, .reversedRange, .emptyClass, .reversedQuantifier,
|
||||
.incompleteEscape, .unterminatedClass:
|
||||
.incompleteEscape, .unterminatedClass, .invalidProperty:
|
||||
true
|
||||
case .unsupported, .badQuantifier, .badEscape, .badClass:
|
||||
false
|
||||
|
||||
@ -120,8 +120,13 @@ struct XSTSSuiteTests {
|
||||
/// Rejecting an attribute `ref` that also carries `form` (src-attribute.3.2) and
|
||||
/// an attribute declaration named `xmlns` (no-xmlns) then caught four more
|
||||
/// invalid schemas: invalid-schemas accepted 207 → 203, no other bucket moved.
|
||||
/// Rejecting a `\p{...}` property whose name can be no XSD charProp under any
|
||||
/// repertoire (empty, the bare `Is`, a non-block name with a non-letter, or `Is`
|
||||
/// followed by a non-block character: `\p{\L}`, `\p{Is}`) while staying lenient
|
||||
/// on a well-formed but unrecognised block name then caught three more invalid
|
||||
/// schemas: invalid-schemas accepted 203 → 200, no other bucket moved.
|
||||
private let knownSchemaValidRejected = 1
|
||||
private let knownSchemaInvalidAccepted = 203
|
||||
private let knownSchemaInvalidAccepted = 200
|
||||
private let knownInstanceValidRejected = 3
|
||||
private let knownInstanceInvalidAccepted = 132
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user