yeptris 0.6.58.1-arm-linux-eabihf → 0.6.60.1-arm-linux-eabihf

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/ext/yeptris_native/version.h +2 -2
  3. data/lib/yeptris/3.4/native.so +0 -0
  4. data/lib/yeptris/document.rb +15 -0
  5. data/lib/yeptris/ffi.rb +112 -0
  6. data/lib/yeptris/psych/visitors.rb +16 -6
  7. data/lib/yeptris/psych.rb +11 -5
  8. data/lib/yeptris/validation.rb +320 -0
  9. data/lib/yeptris/yaml.rb +128 -6
  10. data/lib/yeptris.rb +2 -1
  11. data/libyeptris.so +0 -0
  12. data/vendor/libyeptris/CMakeLists.txt +1 -1
  13. data/vendor/libyeptris/src/CMakeLists.txt +8 -0
  14. data/vendor/libyeptris/src/include/yeptris/emit.h +30 -2
  15. data/vendor/libyeptris/src/include/yeptris/parse.h +52 -0
  16. data/vendor/libyeptris/src/include/yeptris/resolve.h +8 -0
  17. data/vendor/libyeptris/src/include/yeptris/validate.h +259 -15
  18. data/vendor/libyeptris/src/include/yeptris/values.h +8 -2
  19. data/vendor/libyeptris/src/yeptris/cbor/cbor.h +10 -0
  20. data/vendor/libyeptris/src/yeptris/cbor/decode.c +5 -7
  21. data/vendor/libyeptris/src/yeptris/cbor/encode.c +9 -9
  22. data/vendor/libyeptris/src/yeptris/cbor/from_marshal.c +1 -1
  23. data/vendor/libyeptris/src/yeptris/common/error.h +2 -0
  24. data/vendor/libyeptris/src/yeptris/doc.h +20 -0
  25. data/vendor/libyeptris/src/yeptris/emit/emit.c +85 -13
  26. data/vendor/libyeptris/src/yeptris/emit/writer.c +158 -642
  27. data/vendor/libyeptris/src/yeptris/emit/writer.h +15 -1
  28. data/vendor/libyeptris/src/yeptris/events/push.c +28 -3
  29. data/vendor/libyeptris/src/yeptris/events/values.c +24 -0
  30. data/vendor/libyeptris/src/yeptris/marshal/to_json.c +650 -0
  31. data/vendor/libyeptris/src/yeptris/parse/engine.c +121 -40
  32. data/vendor/libyeptris/src/yeptris/parse/stream_iter.c +326 -0
  33. data/vendor/libyeptris/src/yeptris/parse.c +181 -46
  34. data/vendor/libyeptris/src/yeptris/resolve/compat11.c +1 -1
  35. data/vendor/libyeptris/src/yeptris/resolve/core12.c +11 -3
  36. data/vendor/libyeptris/src/yeptris/resolve/full12.c +201 -0
  37. data/vendor/libyeptris/src/yeptris/resolve/json12.c +12 -6
  38. data/vendor/libyeptris/src/yeptris/resolve/resolver.h +20 -0
  39. data/vendor/libyeptris/src/yeptris/validate/compile.c +306 -0
  40. data/vendor/libyeptris/src/yeptris/validate/internal.h +255 -10
  41. data/vendor/libyeptris/src/yeptris/validate/jsonschema.c +1025 -125
  42. data/vendor/libyeptris/src/yeptris/validate/output.c +246 -0
  43. data/vendor/libyeptris/src/yeptris/validate/regexp.c +791 -163
  44. data/vendor/libyeptris/src/yeptris/validate/registry.c +118 -0
  45. data/vendor/libyeptris/src/yeptris/validate/resources.c +601 -0
  46. data/vendor/libyeptris/src/yeptris/validate/stream.c +1155 -0
  47. data/vendor/libyeptris/src/yeptris/validate/validate.c +330 -226
  48. metadata +10 -1
data/lib/yeptris/yaml.rb CHANGED
@@ -22,17 +22,64 @@ module Yeptris
22
22
  # schema: :compat_11 selects Psych/libyaml implicit typing
23
23
  # (yes/no, 0o/octal, sexagesimal); :core_12 (default) is YAML 1.2.
24
24
  #
25
+ # The validation keywords (#882) check BEFORE loading and raise
26
+ # Yeptris::Validation::Error carrying the diagnostics on invalid
27
+ # input: `validate:` rides the engine's schema-family walk (true
28
+ # rides :core_12 — the 1.2 families are the validation families;
29
+ # or an explicit :core_12 / :json_12), `json_schema:` validates
30
+ # against JSON Schema draft 2020-12 (schema bytes or a compiled
31
+ # Yeptris::Validation::Schema).
32
+ #
25
33
  # This surface keeps the Psych contract for EVERY input — including
26
34
  # JSON-shaped ones (`{"a": [1,]}` is legal flow YAML; `"1e3"` is a
27
35
  # Psych String). Strict RFC 8259 semantics live on Yeptris::JSON
28
36
  # (TODO.restructure/31): defaults follow proof, not benchmarks.
29
- def load(yaml, schema: :compat_11)
37
+ def load(yaml, schema: :compat_11, validate: nil, json_schema: nil)
30
38
  yaml = Yeptris.read_input(yaml)
31
39
  yaml = yaml.to_s
40
+ _assert_valid(yaml, validate, json_schema) if validate || json_schema
32
41
  docs = _drain_all(yaml, schema)
33
42
  docs.empty? ? nil : docs.first
34
43
  end
35
44
 
45
+ # The validation face (#882): every diagnostic the engine reports,
46
+ # as plain Yeptris::Validation::Diagnostic values (empty array =
47
+ # valid). Default is the engine's core-family walk; `json_schema:`
48
+ # switches to JSON Schema draft 2020-12 (bytes or a compiled
49
+ # Yeptris::Validation::Schema), `validate:` picks the schema family
50
+ # explicitly (:core_12 / :json_12). Every document of the stream is
51
+ # validated; paths are root-relative per document.
52
+ def validate(yaml, validate: true, json_schema: nil)
53
+ yaml = Yeptris.read_input(yaml)
54
+ _validation_call(yaml.to_s, validate, json_schema)
55
+ end
56
+
57
+ # The boolean posture of validate: true when the engine reports no
58
+ # diagnostics.
59
+ def valid?(yaml, validate: true, json_schema: nil)
60
+ validate(yaml, validate: validate, json_schema: json_schema).empty?
61
+ end
62
+
63
+ # The load-side gate: raises Yeptris::Validation::Error carrying
64
+ # the diagnostics when the input is invalid; silent otherwise.
65
+ def _assert_valid(yaml, validate, json_schema)
66
+ diags = _validation_call(yaml, validate, json_schema)
67
+ raise Validation::Error, diags unless diags.empty?
68
+ end
69
+
70
+ def _validation_call(yaml, validate, json_schema)
71
+ if json_schema
72
+ Validation.validate_schema(yaml, json_schema)
73
+ else
74
+ # `validate: true` rides :core_12 — the family walk has no
75
+ # :compat_11 face (the engine rejects it; resolve schemas are
76
+ # not validation families).
77
+ Validation.validate_family(yaml, schema: validate == true ? :core_12 : validate)
78
+ end
79
+ end
80
+ private_class_method :_validation_call
81
+ private_class_method :_assert_valid
82
+
36
83
  # Psych-semantics safe_load on the native surface (issue #69 —
37
84
  # the entry frameworks actually want): plain data only; a leaf
38
85
  # whose class is not permitted raises Yeptris::Psych::
@@ -60,13 +107,23 @@ module Yeptris
60
107
  #
61
108
  # With a block, every element — documents and, under :collect,
62
109
  # error markers — is yielded in order; the array is returned.
63
- def load_stream(yaml, schema: :compat_11, errors: :raise, &block)
110
+ #
111
+ # The validation keywords (#882) run the whole stream BEFORE
112
+ # loading (the same shapes as load: `validate:` family walk /
113
+ # `json_schema:` JSON Schema 2020-12) and raise
114
+ # Yeptris::Validation::Error on any diagnostics. The engine's
115
+ # report is flat across the stream — diagnostics carry no
116
+ # per-document index (streaming validation is future work, #885) —
117
+ # so the verdict is whole-stream by construction.
118
+ def load_stream(yaml, schema: :compat_11, errors: :raise, validate: nil,
119
+ json_schema: nil, &block)
64
120
  unless %i[raise collect].include?(errors)
65
121
  raise ArgumentError, "errors: must be :raise or :collect (got #{errors.inspect})"
66
122
  end
67
123
 
68
124
  yaml = Yeptris.read_input(yaml)
69
125
  yaml = yaml.to_s
126
+ _assert_valid(yaml, validate, json_schema) if validate || json_schema
70
127
  docs =
71
128
  begin
72
129
  docs = _drain_all(yaml, schema)
@@ -140,6 +197,67 @@ module Yeptris
140
197
  results
141
198
  end
142
199
 
200
+ # The engine capability behind each_document (the CBOR.available?
201
+ # pattern): false when the loaded libyeptris predates the stream
202
+ # iterator — the walk itself raises the stale-engine message at use.
203
+ def each_document?
204
+ FFI::STREAM_ITER
205
+ end
206
+
207
+ # The tolerant per-document walk (engine #921): every document of
208
+ # the stream reaches the block IN STREAM ORDER — a valid document
209
+ # yields (document, nil); a failed document yields (nil, error)
210
+ # and the walk CONTINUES at the next line-start marker, so the
211
+ # valid documents after a bad one are kept (load_stream with
212
+ # errors: :raise would drop the whole stream; :collect recovers by
213
+ # a regex slice split, which quoted scalars spanning marker-looking
214
+ # lines can defeat — the engine iterator frames scanner-accurately,
215
+ # so those documents fail as ONE unit instead of splitting).
216
+ # Errors carry the failed document's own line/column and its
217
+ # stream index. Without a block, an Enumerator over the pairs.
218
+ def each_document(yaml, schema: :compat_11, max_depth: 0, &block)
219
+ return enum_for(:each_document, yaml, schema: schema, max_depth: max_depth) unless block
220
+
221
+ yaml = Yeptris.read_input(yaml)
222
+ yaml = yaml.to_s
223
+ opts = FFI::ParseOptions.new
224
+ opts[:schema] = schema == :compat_11 ? FFI::SCHEMA_11_COMPAT : FFI::SCHEMA_12_CORE
225
+ opts[:max_depth] = max_depth
226
+ it = FFI.yeptris_stream_iter_new(yaml, yaml.bytesize, opts)
227
+ doc_p = ::FFI::MemoryPointer.new(:pointer)
228
+ idx_p = ::FFI::MemoryPointer.new(:size_t)
229
+ line_p = ::FFI::MemoryPointer.new(:uint32)
230
+ col_p = ::FFI::MemoryPointer.new(:uint32)
231
+ begin
232
+ loop do
233
+ st = FFI.yeptris_stream_iter_next(it, doc_p, idx_p)
234
+ doc_ptr = doc_p.read_pointer
235
+ break if st == FFI::OK && doc_ptr.null? # the stream is over
236
+
237
+ index = FFI.read_c_size_t(idx_p)
238
+ if st == FFI::OK
239
+ doc = Document.without_finalizer(doc_ptr)
240
+ begin
241
+ yield doc.to_ruby, nil
242
+ ensure
243
+ doc.free
244
+ end
245
+ else
246
+ FFI.yeptris_stream_iter_status(it, line_p, col_p)
247
+ reason = st == FFI::ERROR_DEPTH ? "depth limit exceeded" : "parse error"
248
+ yield nil,
249
+ ParseError.new(
250
+ "stream document #{index}: #{reason} at line #{line_p.read_uint32}, " \
251
+ "column #{col_p.read_uint32}"
252
+ )
253
+ break if st == FFI::ERROR_MEMORY || st == FFI::ERROR_ENCODING
254
+ end
255
+ end
256
+ ensure
257
+ FFI.yeptris_stream_iter_free(it)
258
+ end
259
+ end
260
+
143
261
  # The Marshal fast path when the loaded libyeptris has it (>= 0.1.11
144
262
  # era builds), falling back to the columnar drain and finally the
145
263
  # record drain — one code path, the fastest the library offers.
@@ -176,8 +294,11 @@ module Yeptris
176
294
  # (TODO.impl/11 phase 3). Strings are emitted plain only when the
177
295
  # resolver round-trips them as strings — everything else takes a
178
296
  # quoted style, so dump(load(x)) == x for the scalar types.
179
- def dump(obj, canonical: false, header: false)
180
- BulkBuilder.dump(obj, canonical: canonical, header: header)
297
+ # width: the emitter's best_width (the engine wraps flow
298
+ # collections after a value when the line exceeds it; 0/nil rides
299
+ # the engine default of 80 — emit.h 13B).
300
+ def dump(obj, canonical: false, header: false, width: nil)
301
+ BulkBuilder.dump(obj, canonical: canonical, header: header, width: width)
181
302
  end
182
303
 
183
304
 
@@ -228,7 +349,7 @@ module Yeptris
228
349
  Yeptris::FFI::BUILD_SEQ => SEQ_ENTRY,
229
350
  Yeptris::FFI::BUILD_END => END_ENTRY }.freeze
230
351
 
231
- def dump(obj, canonical: false, header: false)
352
+ def dump(obj, canonical: false, header: false, width: nil)
232
353
  parts = []
233
354
  blob = String.new(encoding: Encoding::BINARY)
234
355
  off = [0]
@@ -243,7 +364,8 @@ module Yeptris
243
364
  bblob = ::FFI::MemoryPointer.from_string(blob)
244
365
  rc = doc.build_entries(buf, parts.length, bblob, blob.bytesize)
245
366
  raise DumpError, "document_build failed: #{rc}" unless rc == FFI::OK
246
- doc.serialize(canonical: canonical, explicit_doc_start: header)
367
+ doc.serialize(canonical: canonical, best_width: width || 0,
368
+ explicit_doc_start: header)
247
369
  ensure
248
370
  doc&.free
249
371
  end
data/lib/yeptris.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  module Yeptris
4
4
  # The gem's version lives in the parent namespace's file — the last
5
5
  # internal require (yeptris/version) retired with it.
6
- VERSION = "0.6.58.1".freeze
6
+ VERSION = "0.6.60.1".freeze
7
7
 
8
8
  # Informational notices are OPT-IN (yeptris-ruby#217): consumers
9
9
  # embed yeptris inside CLIs that assert clean stderr, and a
@@ -54,6 +54,7 @@ module Yeptris
54
54
  autoload :ValueML, "yeptris/valueml"
55
55
  autoload :Psych, "yeptris/psych"
56
56
  autoload :Schema, "yeptris/schema"
57
+ autoload :Validation, "yeptris/validation"
57
58
  autoload :CBOR, "yeptris/cbor"
58
59
  end
59
60
 
data/libyeptris.so CHANGED
Binary file
@@ -3,7 +3,7 @@
3
3
  cmake_minimum_required(VERSION 3.20)
4
4
 
5
5
  project(yeptris
6
- VERSION 0.6.58
6
+ VERSION 0.6.60
7
7
  DESCRIPTION "Ultra-fast YAML 1.2 parser, emitter and streamer in C"
8
8
  LANGUAGES C CXX
9
9
  )
@@ -29,6 +29,7 @@ set(YEPTRIS_SOURCES
29
29
  yeptris/dom/mapindex.c
30
30
  yeptris/dom/mutate.c
31
31
  yeptris/parse.c
32
+ yeptris/parse/stream_iter.c
32
33
  yeptris/build.c
33
34
  yeptris/events/capture.c
34
35
  yeptris/events/push.c
@@ -40,16 +41,23 @@ set(YEPTRIS_SOURCES
40
41
  yeptris/resolve/core12.c
41
42
  yeptris/resolve/compat11.c
42
43
  yeptris/resolve/json12.c
44
+ yeptris/resolve/full12.c
43
45
  yeptris/parse/numbers.c
44
46
  yeptris/events/values.c
45
47
  yeptris/schema.c
46
48
  yeptris/validate/regexp.c
47
49
  yeptris/validate/validate.c
50
+ yeptris/validate/compile.c
51
+ yeptris/validate/resources.c
48
52
  yeptris/validate/jsonschema.c
53
+ yeptris/validate/registry.c
54
+ yeptris/validate/output.c
55
+ yeptris/validate/stream.c
49
56
  yeptris/tape.c
50
57
  yeptris/plan.c
51
58
 
52
59
  yeptris/marshal.c
60
+ yeptris/marshal/to_json.c
53
61
  yeptris/visit/json_visit.c
54
62
  yeptris/visit/yaml_visit.c
55
63
  yeptris/visit/dom_visit.c
@@ -24,7 +24,14 @@ extern "C" {
24
24
  #endif
25
25
 
26
26
  /* Emission options (13B). Versioned by size: initialize with
27
- * {sizeof(yeptris_emit_options)} so future fields stay optional. */
27
+ * {sizeof(yeptris_emit_options)} so future fields stay optional.
28
+ *
29
+ * Deliberately omitted: a flowLevel knob (libyaml's best_width +
30
+ * default_flow_style interplay). The engine's style chooser is
31
+ * recorded-style driven — flow is whatever the document recorded
32
+ * (plus the fixed canonical/JSON forms) — so there is no "switch to
33
+ * flow past level N" decision to expose; revisit only if a binding
34
+ * face actually needs PyYAML's default_flow_style mapping. */
28
35
  typedef struct yeptris_emit_options {
29
36
  uint32_t size; /* sizeof(yeptris_emit_options) */
30
37
  int canonical; /* fixed form: flow collections, quoted strings,
@@ -32,13 +39,34 @@ typedef struct yeptris_emit_options {
32
39
  * output re-serializes byte-identically */
33
40
  int best_width; /* 0 = library default (80): flow collections
34
41
  * wrap after a value when the current line
35
- * exceeds the width (13B) */
42
+ * exceeds the width (13B); with block_fold
43
+ * it is also the fold column for block
44
+ * scalars (#903) */
36
45
  int explicit_doc_start; /* nonzero: every document carries the
37
46
  * leading --- marker (Psych/libyaml's
38
47
  * implicit=false parity). Default 0: a
39
48
  * single document is emitted bare. Only
40
49
  * read when the caller's struct is large
41
50
  * enough (size-versioned). */
51
+ int best_indent; /* (#903) block indentation per level: the
52
+ * content column of a nested block mapping
53
+ * and the "- " item level. Out of range
54
+ * (< 2 or > 9, libyaml's clamp) or 0 = the
55
+ * library default 2. Only read when the
56
+ * caller's struct is large enough. */
57
+ int block_fold; /* (#903) nonzero: plain and single-quoted
58
+ * scalars in block context fold at
59
+ * best_width the way libyaml/Psych/PyYAML
60
+ * do — at an interior single space past the
61
+ * width the break replaces the space and
62
+ * the continuation re-indents to
63
+ * parent_col + best_indent. Default 0:
64
+ * block output is width-invariant (byte-
65
+ * identical with releases before the
66
+ * option). Keys and flow members never
67
+ * fold; canonical/JSON keep their fixed
68
+ * forms. Only read when the caller's
69
+ * struct is large enough. */
42
70
  } yeptris_emit_options;
43
71
 
44
72
  /* Options-aware entries; opts == NULL selects the fidelity mode
@@ -41,6 +41,58 @@ YEPTRIS_API YeptrisDocument yeptris_parse_ex(const char* buf, size_t len,
41
41
  const YeptrisParseOptions* opts,
42
42
  YeptrisStatus* status);
43
43
 
44
+ /* ---- tolerant per-document stream iteration (#921) ----------------------
45
+ *
46
+ * load_stream parses the whole stream and aborts on the first bad
47
+ * document; this iterator frames documents engine-side (the abort-at-
48
+ * DOCUMENT_END run — scanner-accurate: a quoted scalar spanning a
49
+ * marker-looking line never splits) and reports failures PER DOCUMENT:
50
+ * a parse-class error surfaces as the step's status with NULL *out, the
51
+ * error channel carrying the failed document's own line/col (each run
52
+ * starts at the frame), and the iterator resynced to the next line-
53
+ * start marker — the host keeps calling and keeps the valid documents.
54
+ *
55
+ * yeptris_stream_iter* it = yeptris_stream_iter_new(buf, len, &opts);
56
+ * YeptrisDocument doc;
57
+ * size_t index;
58
+ * YeptrisStatus st;
59
+ * while ((st = yeptris_stream_iter_next(it, &doc, &index)) == YEPTRIS_OK && doc != NULL) {
60
+ * // doc is document `index` of the stream; free it with
61
+ * // yeptris_document_free
62
+ * }
63
+ * // st == OK && doc == NULL: the stream is over; st != OK: document
64
+ * // `index` failed (per-document line/col via
65
+ * // yeptris_stream_iter_status), keep iterating.
66
+ *
67
+ * Memory: the caller owns each *out (yeptris_document_free). The
68
+ * iterator borrows `buf` until free. Each document parses twice (the
69
+ * boundary run + the slice parse) — the tolerance contract is the
70
+ * point; a single-pass upgrade rides the same seam when needed.
71
+ */
72
+ typedef struct yeptris_stream_iter yeptris_stream_iter;
73
+
74
+ /* The iterator borrows `buf` until free; `opts` is borrowed (may be
75
+ * NULL: the 12_CORE defaults). NULL on arg/alloc failure. */
76
+ YEPTRIS_API yeptris_stream_iter* yeptris_stream_iter_new(const char* buf, size_t len,
77
+ const YeptrisParseOptions* opts);
78
+
79
+ /* The next document: OK + *out = the document (the caller frees it);
80
+ * a parse/DEPTH-class DOCUMENT failure: that status + *out = NULL +
81
+ * the error channel set for THAT document — the iterator has already
82
+ * resynced, keep calling; OK + *out = NULL: the stream is over;
83
+ * MEMORY/ENCODING: stream-fatal, the iterator is done. *index (may be
84
+ * NULL) is the 0-based stream document index this step consumed
85
+ * (failures consume an index too — the yield order is the stream's). */
86
+ YEPTRIS_API YeptrisStatus yeptris_stream_iter_next(yeptris_stream_iter* it, YeptrisDocument* out,
87
+ size_t* index);
88
+
89
+ /* The LAST step's per-document verdict and its 1-based line/col
90
+ * (0/0 when the last step was a success or the stream end). */
91
+ YEPTRIS_API YeptrisStatus yeptris_stream_iter_status(const yeptris_stream_iter* it, uint32_t* line,
92
+ uint32_t* col);
93
+
94
+ YEPTRIS_API void yeptris_stream_iter_free(yeptris_stream_iter* it);
95
+
44
96
  #ifdef __cplusplus
45
97
  }
46
98
  #endif
@@ -46,6 +46,14 @@ typedef enum {
46
46
  YEPTRIS_SCHEMA_11_COMPAT, /* libyaml/Psych implicit typing */
47
47
  YEPTRIS_SCHEMA_12_JSON, /* spec 10.2: JSON productions; plain
48
48
  * scalars matching none are errors (#882) */
49
+ YEPTRIS_SCHEMA_12_FULL, /* the full 1.2 family (#906 slice 3):
50
+ * core typing + RFC3339-era timestamps
51
+ * (spec 2.22's four forms; the yaml.org
52
+ * type repository carried forward) and
53
+ * the merge/value words; !!binary rides
54
+ * as passthrough. A validation family:
55
+ * explicit !!timestamp content must
56
+ * re-resolve through the classifier. */
49
57
  } YeptrisSchema;
50
58
 
51
59
  /* Canonical tag URI for a core id ("tag:yaml.org,2002:str"); NULL for