odin-jsonschema

Implementation of JSON schema for Odin
Log | Files | Refs | LICENSE

resolve.odin (1742B)


      1 package jschema
      2 
      3 import "core:os"
      4 import "core:path/filepath"
      5 import "core:strings"
      6 
      7 // Resolves every pending $ref, loading relative schema files on demand.
      8 // Loading a file can append more pending refs, so this drains by index.
      9 @(private)
     10 resolve_refs :: proc(b: ^Builder) -> Error {
     11 	for i := 0; i < len(b.pending); i += 1 {
     12 		pending := b.pending[i]
     13 
     14 		fragment := pending.ref
     15 		file_part := ""
     16 		if hash := strings.index_byte(pending.ref, '#'); hash >= 0 {
     17 			file_part = pending.ref[:hash]
     18 			fragment = pending.ref[hash:]
     19 		} else {
     20 			file_part = pending.ref
     21 			fragment = "#"
     22 		}
     23 
     24 		file_key := pending.file
     25 		if file_part != "" {
     26 			file_key = resolve_file(b, file_part, pending.dir) or_return
     27 		}
     28 
     29 		node, found := b.pointers[strings.concatenate({file_key, fragment})]
     30 		if !found {
     31 			return Resolve_Error{path = pending.file, ref = pending.ref}
     32 		}
     33 		b.pool.nodes[pending.node].ref = node
     34 	}
     35 	return nil
     36 }
     37 
     38 // Loads (once) the schema file at `name` relative to `dir` and registers its
     39 // root as a named def. Returns the file's pointer-map key.
     40 @(private)
     41 resolve_file :: proc(b: ^Builder, name: string, dir: string) -> (key: string, err: Error) {
     42 	path := name
     43 	if !filepath.is_abs(name) {
     44 		path, _ = filepath.join({dir, name})
     45 	}
     46 	if cleaned, aerr := filepath.abs(path); aerr == nil {
     47 		path = cleaned
     48 	}
     49 
     50 	if _, loaded := b.files[path]; loaded {
     51 		return path, nil
     52 	}
     53 
     54 	data, rerr := os.read_entire_file_from_path(path, context.allocator)
     55 	if rerr != nil {
     56 		return "", IO_Error{path = path, error = rerr}
     57 	}
     58 
     59 	root := parse_document(b, data, path, path, filepath.dir(path)) or_return
     60 	b.files[path] = root
     61 	stem := filepath.stem(filepath.base(path))
     62 	append(&b.pool.defs, Def{name = stem, node = root})
     63 	return path, nil
     64 }