File size: 2,470 Bytes
7e2c39a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
"""Minimal output-schema validation for AI generators.

A spec is a dict: field name -> rule dict with keys:
    type:      "str" | "list"
    min_len /  max_len: for str, character bounds; for list, item-count bounds
    count:     exact list length (e.g. exactly 3 DM hooks)
    item_min / item_max: character bounds for each list item (str items)

validate() returns a list of human-readable problems (empty = valid).
Deliberately dependency-free so every Space stays light.
"""


def validate(data, spec) -> list[str]:
    problems = []
    if not isinstance(data, dict):
        return [f"expected a JSON object, got {type(data).__name__}"]
    for field, rule in spec.items():
        if field not in data:
            problems.append(f"missing field '{field}'")
            continue
        value = data[field]
        ftype = rule.get("type", "str")
        if ftype == "str":
            if not isinstance(value, str):
                problems.append(f"'{field}' must be a string")
                continue
            v = value.strip()
            if rule.get("min_len") and len(v) < rule["min_len"]:
                problems.append(f"'{field}' too short (min {rule['min_len']} chars)")
            if rule.get("max_len") and len(v) > rule["max_len"]:
                problems.append(f"'{field}' too long (max {rule['max_len']} chars)")
        elif ftype == "list":
            if not isinstance(value, list):
                problems.append(f"'{field}' must be a list")
                continue
            if "count" in rule and len(value) != rule["count"]:
                problems.append(f"'{field}' must have exactly {rule['count']} items")
            if rule.get("min_len") and len(value) < rule["min_len"]:
                problems.append(f"'{field}' needs at least {rule['min_len']} items")
            if rule.get("max_len") and len(value) > rule["max_len"]:
                problems.append(f"'{field}' allows at most {rule['max_len']} items")
            for i, item in enumerate(value):
                if not isinstance(item, str):
                    problems.append(f"'{field}[{i}]' must be a string")
                    continue
                if rule.get("item_min") and len(item.strip()) < rule["item_min"]:
                    problems.append(f"'{field}[{i}]' too short")
                if rule.get("item_max") and len(item.strip()) > rule["item_max"]:
                    problems.append(f"'{field}[{i}]' too long")
    return problems