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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
//! Public entry points: `parse_schema*`.
//!
//! Split out of `lib.rs` (cratestack#916) once every entry point that
//! actually knows a path started tagging its returned [`SchemaError`]s with
//! it via `SchemaError::with_file` — the extra couple of lines per function
//! pushed `lib.rs` (already carrying the full module declaration list) past
//! the 200-line ceiling.
use Path;
use Arc;
use crate::;
/// File identity used when a caller parses a schema with no path to give.
/// Prefer [`parse_schema_named`] whenever a path is known: it is what makes
/// a rendered diagnostic name the file.
pub const ANONYMOUS_SCHEMA: &str = "<schema>";
/// Parse and validate, reporting **every** independent problem rather than
/// only the first.
///
/// [`parse_schema_named`] stops at the first error, which is right for a
/// compiler or a CLI: the build is failing either way, and one clear message
/// beats a cascade. It is wrong for an editor, where stopping early means the
/// author fixes one error, saves, and is handed the next — one round trip per
/// mistake.
///
/// Semantics worth knowing:
///
/// * A **syntax** error still yields exactly one diagnostic. Parsing has no
/// recovery, so there is no second error to report — everything after the
/// failure is unparsed, not valid.
/// * **Validation** errors are collected in stages, and a stage runs only when
/// every earlier stage was clean. Several validators document that they
/// assume an earlier one passed, and running them over already-rejected input
/// produces cascades pointing at the wrong places. Within a stage, every
/// declaration reports independently — three models each naming a type that
/// does not exist produce three diagnostics, not three round trips.
/// * The schema is returned only when there are no errors at all, matching
/// [`parse_schema_named`].
///
/// The first element of the returned `Vec` is always the same error
/// [`parse_schema_named`] would have returned; both go through one set of
/// checks in one order, so they cannot drift apart.
/// Parse a `.cstack` source into a [`cratestack_core::Schema`] WITHOUT
/// running [`validate::validate_schema`].
///
/// Prefer [`parse_schema`] for any new source — this exists for two
/// legitimate cases where the validated pipeline understates what a
/// `Schema` value can actually be:
///
/// 1. A committed `migrations/*/schema.snapshot.json` can predate a
/// validation rule added later. `cratestack-cli`'s `migrate diff`
/// deserializes that "previous" snapshot directly and never re-runs
/// `validate_schema` on it (only the *new* side, parsed fresh from the
/// `.cstack` source, goes through [`parse_schema_file`]) — so an emitter
/// can still legitimately be handed a shape the current validator would
/// reject at the source level.
/// 2. Tests that deliberately exercise an emitter's rendering logic for
/// such an already-invalid shape, to prove the emitter itself still
/// behaves sanely if that shape arrives via (1) — see
/// `cratestack-migrate`'s `emit::postgres::tests::enums` for an example
/// (a list-valued enum column, rejected by cratestack#229/#236 at parse
/// time, but still real input to the Postgres emitter via a pre-#236
/// snapshot).