validate
Stable function · Validation
Tier: stable · Kind: function · Topic: Validation
| Julia | TypeScript | Python | Rust | Go |
|---|---|---|---|---|
validate | validate | validate | validate | Validate |
Julia
validate(file::EsmFile)
validate(file::EsmFile) -> ValidationResult
Complete validation combining schema, structural, and unit validation. Returns ValidationResult with all errors and warnings.
Example (validate)
result = validate(doc)
@assert result isa ValidationResult
@assert result.is_valid
# A document that loads fine but uses a variable it never declares. Validation
# reports the problem in the result rather than throwing.
bad = validate_path(joinpath(FIXTURES, "invalid.esm"))
@assert !bad.is_valid
err = only(bad.structural_errors)
println(err.path, ": ", err.message)
@assert err.message == "Variable 'k' referenced in equation is not declared"
@assert err.path == "/models/Broken/equations/0/rhs"
TypeScript
function validate(document: EsmFile | object, options?: ValidateOptions): ValidationResult
Validate a TYPED ESM DOCUMENT and return a structured validation result.
API_SPEC.md §8 item 13: validate takes a typed document in EVERY binding.
To validate JSON text, call validateText
.
Passing a string is rejected at compile time by the signature and at runtime by an explicit guard, rather than silently doing something else.
Parameters
document— a loaded ESM document (or a plain object of the same shape)options— OptionalValidateOptions; passbasePathto let relative{ref}/ template-import targets be opened and resolved.
Returns
ValidationResult with validation status and errors
Example (validate)
// A good document validates cleanly.
const good = validate(loadPath(fixture('decay.esm')))
assert.equal(good.is_valid, true)
assert.deepEqual(good.structural_errors, [])
// `validate` reports problems in its result; it does not throw. invalid.esm
// uses a variable `k` that its model never declares.
const bad = validateText(readFileSync(fixture('invalid.esm'), 'utf8'))
assert.equal(bad.is_valid, false)
assert.equal(bad.schema_errors.length, 0)
const [err] = bad.structural_errors
assert.equal(err.code, 'undefined_variable')
assert.equal(err.path, '/models/Broken/equations/0/rhs')
assert.match(err.message, /Variable "k" referenced in equation is not declared/)
// Loading a structurally invalid document still succeeds. Unit warnings found
// while loading go to `console.warn` unless you collect them yourself.
const warnings: UnitWarning[] = []
const broken = loadPath(fixture('invalid.esm'), { onUnitWarning: (w) => warnings.push(w) })
assert.equal(validate(broken).is_valid, false)
assert.match(warnings[0].message, /Unknown variable: k/)
// Text that is not JSON at all is a `ParseError`, thrown at load time.
assert.throws(() => loadString('{ not json'), ParseError)
Python
validate(esm_file: EsmFile, *, base_path: str | None = None) -> ValidationResult
Validate a parsed ESM document against structural and unit requirements.
esm_file is a typed EsmFile
— the
one input type validate accepts in every binding (API_SPEC.md §8
item 13). It does not accept a path, JSON text or a raw dict; use
the explicit entry points instead:
- a filesystem path ->
validate_path; - JSON text ->
validate_text; - an already-decoded
dict->validate(load_document(data)).
This function implements comprehensive validation including:
- Equation-unknown balance
- Reference integrity (variable refs, scoped refs, event affects, coupling refs, operator refs)
- Reaction consistency (species declared, positive stoichiometries, no null-null, rate refs)
- Event consistency (condition types, affect vars, functional affect refs)
Parameters
esm_file(EsmFile) — The parsedEsmFileto validate.base_path(str | None) — Directory that relative{"ref": ...}subsystem/model mounts (§4.7) andexpression_template_imports(§9.7.2) resolve against.A document that came through
load_pathresolved its mounts already, so this mainly matters on thevalidate_text/validate_pathpaths, which forward it to the loader: text carries no location of its own, and without an anchor every subsystem-ref and template-import fixture becomes unsatisfiable. A MISSING target then yieldsunresolved_subsystem_ref(or the template-import equivalent) at the mount’s pointer, and a PRESENT one validates through.
Returns
ValidationResult— ValidationResult containing schema_errors, structural_errors, unit_warnings, and is_valid flag
Raises
TypeError— ifesm_fileis not anEsmFile.
Example (validate)
result = earthsci_ast.validate(doc)
assert result.is_valid
assert result.schema_errors == [] and result.structural_errors == []
# validate_path reports problems in the result; it does not raise.
bad = earthsci_ast.validate_path(FIXTURES / "invalid.esm")
assert not bad.is_valid
error = bad.structural_errors[0]
print(error.code, error.path, error.message)
assert error.code == "undefined_variable"
assert "'k'" in error.message
# Loading the same file raises, because loading validates too.
try:
earthsci_ast.load_path(FIXTURES / "invalid.esm")
except earthsci_ast.SchemaValidationError as exc:
assert "'k'" in str(exc)
else:
raise AssertionError("loading invalid.esm should fail")
Rust
pub fn validate(esm_file: &EsmFile) -> ValidationResult
Perform structural validation on an ESM file
Note: This function performs ONLY structural validation, not schema validation.
For comprehensive validation (both schema and structural), use validate_text() instead.
This function runs the structural checks (delegating to
crate::structural and crate::coupling):
- All variable references are defined (including scoped refs resolved via the subsystem hierarchy)
- Equation-unknown balance (ODE count vs. state variables)
- Observed variables carry expressions
- Discrete/continuous event references
- Reaction species/stoichiometry consistency
- Coupling-entry well-formedness
- Dimensional consistency of equations — reported as
unit_warnings, never as errors
Arguments
esm_file- The ESM file to validate (already parsed and schema-validated)
Returns
ValidationResult- Structural validation results (schema_errors will always be empty)
Examples
use earthsci_ast::{validate, load_string, EsmFile, Metadata};
let json_str = r#"
{
"esm": "1.0.0",
"metadata": {"name": "test"},
"models": {"simple": {"variables": {}, "equations": []}}
}
"#;
// First load and parse (includes schema validation)
let esm_file = load_string(json_str).unwrap();
// Then do structural validation
let result = validate(&esm_file);
assert!(result.is_valid);
assert!(result.schema_errors.is_empty()); // Always empty for this function
Example (validate)
let good = load_path(fixture("decay.esm"))?;
let result = validate(&good);
assert!(result.is_valid);
assert!(result.schema_errors.is_empty() && result.structural_errors.is_empty());
// invalid.esm is well-formed JSON that matches the schema, so it loads;
// validation then reports the undeclared variable `k` as a structural
// error. Validation returns a result object, it does not fail.
let bad = load_path(fixture("invalid.esm"))?;
let result = validate(&bad);
assert!(!result.is_valid);
for err in &result.structural_errors {
println!("{}: [{:?}] {}", err.path, err.code, err.message);
}
assert!(result.structural_errors.iter().any(|e| e.message.contains("'k'")));
// `validate_text` starts from the JSON text, so a document that does not
// even load is reported in the same result shape instead of as an error.
let text = std::fs::read_to_string(fixture("invalid.esm"))?;
let from_text = validate_text(&text, None);
assert!(!from_text.is_valid);
let not_json = validate_text("{ \"esm\": ", None);
assert!(!not_json.is_valid);
Go
func Validate(file *ESMFile) *ValidationResult
Validate performs semantic validation of an already-parsed ESM document and returns the four-field ValidationResult of esm-libraries-spec §3.4.
Canonical validate (API_SPEC.md §8 items 12 and 13): the input is a TYPED DOCUMENT in every binding, and the return is the four-field shape in every binding. ValidateStructural still offers the message-oriented DetailedValidationResult form.
SchemaErrors is always EMPTY, exactly as Rust’s validate documents: a *ESMFile can only exist by having come through LoadString/LoadPath/ LoadDocument, all of which schema-validate and refuse to return a document that fails. Validating text that has NOT been through the schema is ValidateText’s job.
IsValid counts hard structural errors only. Warning-level findings (StructuralError.Level == “warning”, e.g. duplicate_reaction_species) are advisory and do not invalidate the document.
Example (edit)
doc, err := esm.LoadPath(fixture("decay.esm"))
if err != nil {
log.Fatal(err)
}
units, desc := "mol", "Amount decayed so far"
model := esm.AddVariable(doc.Models["Decay"], "decayed", esm.ModelVariable{
Type: "unknown", Units: &units, Description: &desc,
})
eq, err := esm.ParseEquation("decayed = 100 - N")
if err != nil {
log.Fatal(err)
}
model = esm.AddEquation(model, *eq)
doc.Models["Decay"] = model
fmt.Println(len(model.Equations), esm.Validate(doc).IsValid)
text, err := esm.ToJSON(doc)
if err != nil {
log.Fatal(err)
}
fmt.Println(strings.Contains(text, `"decayed"`))
path := filepath.Join(dir, "decay-edited.esm")
if err := esm.WritePath(doc, path); err != nil {
log.Fatal(err)
}
reread, err := esm.LoadPath(path)
if err != nil {
log.Fatal(err)
}
fmt.Println(sortedKeys(reread.Models["Decay"].Variables))
From docs/api/examples/go/edit_test.go
Example (validate)
doc, err := esm.LoadPath(fixture("decay.esm"))
if err != nil {
log.Fatal(err)
}
fmt.Println(esm.Validate(doc).IsValid)
// invalid.esm is schema-clean but its equation reads an undeclared `k`.
text, err := os.ReadFile(fixture("invalid.esm"))
if err != nil {
log.Fatal(err)
}
result := esm.ValidateText(string(text))
fmt.Println(result.IsValid)
for _, e := range result.StructuralErrors {
fmt.Println(e.Code, e.Path)
fmt.Println(e.Message)
}