| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950 |
- from collections.abc import Mapping
- from typing import Any
- _UNSUPPORTED_REGEX_TOKENS = frozenset({".", "^", "$", "*", "+", "?", "{", "}", "[", "]", "|", "(", ")", "\\"})
- def match_pattern_properties(
- pattern_properties: Mapping[str, Any],
- key: str,
- ) -> tuple[list[Any], list[str]]:
- """Match JSON Schema patternProperties using a safe literal+anchor subset.
- Supported forms:
- - "token" -> key contains token
- - "^token" -> key starts with token
- - "token$" -> key ends with token
- - "^token$" -> key equals token
- Any pattern using additional regex tokens is treated as unsupported and skipped.
- The caller can log unsupported patterns using the returned list.
- """
- if not pattern_properties:
- return [], []
- matched_schemas: list[Any] = []
- unsupported_patterns: list[str] = []
- for pattern, schema in pattern_properties.items():
- anchored_start = pattern.startswith("^")
- anchored_end = pattern.endswith("$")
- literal = pattern[1 if anchored_start else 0 : -1 if anchored_end else None]
- if any(token in literal for token in _UNSUPPORTED_REGEX_TOKENS):
- unsupported_patterns.append(pattern)
- continue
- if anchored_start and anchored_end:
- is_match = key == literal
- elif anchored_start:
- is_match = key.startswith(literal)
- elif anchored_end:
- is_match = key.endswith(literal)
- else:
- is_match = literal in key
- if is_match:
- matched_schemas.append(schema)
- return matched_schemas, unsupported_patterns
|