Input text
한국어.
Text in specifications and data is a sequence of Unicode scalar values: code points U+0000 to U+D7FF and U+E000 to U+10FFFF. Every runtime applies the rule below at the same operations, in the same order, with the same failures. Text that breaks it is rejected. It is never replaced, for example with U+FFFD, and never passed on to a result.
Invalid text
- CUIT-001 JavaScript string: A surrogate code unit that is not part of a high and low pair
- CUIT-002 PHP, Go and C string: Bytes that are not UTF-8, including an encoded surrogate, an overlong form and a value above U+10FFFF
- CUIT-003 Rust
String: None; the type holds only Unicode scalar values - CUIT-004 JSON text: A
\uescape of a surrogate that is not part of a high and low pair, such as"\ud800"or the reversed pair"\udc00\ud800"
The rule covers every string value and every object member name at any depth. Numbers,
booleans and null hold no text.
Operations and order
Each operation checks its text before any other check, including the argument shape checks. It checks, in this order:
- CUIT-005 The specification, then the composition files it reads.
- CUIT-006 Its other arguments, in the order of the table.
- CUIT-007 Its options, in code point order of their names.
- CUIT-008
validate— Specification:spec,files; Other arguments:data; Options:basepath - CUIT-009
validateList,validateDetail— Specification:spec,files; Options:basepath - CUIT-010
compileForm— Specification:spec,files; Options:basepath,keyPrefix - CUIT-011
bindForm,bindButtons,createForm— Other arguments:template,data; Options:idPrefix,keyPrefix,language,unsupported - CUIT-012
buildList,renderList— Specification:spec,files; Other arguments:rows; Options:basepath,data,language,layout - CUIT-013
buildDetail,renderDetail— Specification:spec,files; Other arguments:record; Options:basepath,data,language,layout - CUIT-014 Form
setData— Other arguments:data - CUIT-015 Form
setValue— Other arguments:path,value - CUIT-016 Form
getValue— Other arguments:path - CUIT-017 Form
addRow— Other arguments:path; Options:afterKey,key,value - CUIT-018 Form
copyRow— Other arguments:path,key; Options:afterKey,key - CUIT-019 Form
removeRow,moveRow— Other arguments:path,key - CUIT-020 Form
rekeyRow— Other arguments:path,oldKey,newKey
The names are the documented argument and option names; each runtime's own spelling, such as
KeyPrefix in Go or key_prefix in Rust, reports the same name. An option that the caller does
not give is not checked. An operation that composes with a custom loader instead of files
checks each document when the loader returns it.
Within one value the check visits array items in index order. For an object it first checks every member name, then visits the members in code point order of their names. The first failure found is reported: invalid text, or a value beyond the value limits.
Value limits
The check walks each value as the JSON tree it denotes, and the same walk bounds it. A JavaScript array or object, a PHP array or object and a Go map, slice or ordered object can appear at more than one place of one value: through sharing, through a PHP reference, or because it contains itself. The walk visits such a container at every place, as the tree holds it there. A value is beyond its limits when:
- CUIT-021 it holds more than 1,000,000 nodes, where each array, object, string, number, boolean and
nullof the tree is a node, the value itself included; or - CUIT-022 it nests more than 512 levels of arrays and objects, the value itself being the first level.
A value that contains itself nests without end, so it is always beyond them. The walk stops at the first failure in its order, so it visits at most 1,000,001 nodes whatever tree a value denotes. Invalid text that the walk meets before a limit is reported as invalid text, and a limit that it passes first is reported as the limit.
The limits apply to every checked value, the specification and the composition files included,
as an input failure that names the value. A custom loader's document is named files.
Go's value entries take maps, slices and *compose.OMap values that can share nodes, so Go
applies the limits like JavaScript and PHP. A Rust serde_json::Value owns each of its nodes: it
cannot share a container or contain itself, so a shared container cannot appear twice in a value.
Rust's value entries count nodes and levels: the walk costs no more than building it.
The PHP library's value copies and the extension's value conversion apply the same limits to
every value they convert, including members that no check walks, such as a member of a button
that the markup does not read. There the failure is the value failure
Recursive or excessively nested PHP value of the PHP extension.
Failures
A failure in the specification or a composition file is a composition load failure:
- CUIT-023 code
INVALID_TEXT; - CUIT-024 message
Text must be Unicode scalar values; - CUIT-025 location: the path of the string joined with
., where an array item is its index. An invalid member name is located at the object that holds it. In a file, the path starts with the file name. An invalid file name, and an invalid member name of the specification root, are located at the empty path.
A failure in any other argument or option is an input failure:
- CUIT-026 code
INVALID_FORM_INPUT; - CUIT-027 message
Text must be Unicode scalar values: {name}, where{name}is the argument name, oroptions.and the option name, followed by the path inside the value, for exampledata.rows.k1.nameoroptions.data.admin; - CUIT-028 an empty location.
A value beyond the value limits is an input failure in every argument and option:
-
CUIT-029 code
INVALID_FORM_INPUT; -
CUIT-030 message
Recursive or excessively nested value: {name}, where{name}isspec,files, the argument name, oroptions.and the option name, with no path; -
CUIT-031 an empty location.
-
CUIT-041 Each implementation reports a load failure and an input failure with the error types that its entry of this list names:
- JavaScript: a load failure is
ComposeLoadError, and an input failure isFormInputError. - PHP and PHP extension: in validation a load failure is
ComposeLoadError, and an input failure isFormInputError; in generation a load failure isComposeLoadError, and an input failure isFormError. - Go: a load failure is
*compose.ComposeLoadError; an input failure is*validate.FormInputErrorin validation and an error with the message in generation. - Rust: a load failure is
ComposeLoadErrorinValidateError::LoadorFormError, and an input failure isFormInputErrorinValidateError::InputorFormError. - Python: in validation a load failure is
ComposeLoadError, and an input failure isFormInputError; in generation a load failure isComposeLoadError, and an input failure isFormError.
- JavaScript: a load failure is
-
CUIT-037 JavaScript:
JSON.parsekeeps each escape as a code unit. -
CUIT-038 Go:
compose.DecodeOrdered,generator.DecodeJSONand theValidateJSON,ValidateListJSONandValidateDetailJSONentries keep an escaped surrogate as its three bytes and keep bytes that are not UTF-8, so the check reports both.encoding/jsonalone replaces them.compose.DecodeRawMemberssplits an object without decoding its values.generator.CheckBindTextchecks a decoded template beforeFormTemplatedecoding, whose JSON encoding would replace invalid text. -
CUIT-039 PHP:
Polyspec\Crudui\Validator\Support\JsonText::decodereturns whatjson_decode($json, false, 512, JSON_THROW_ON_ERROR)returns and keeps an escaped surrogate as its three bytes. The class has no dependencies. -
CUIT-040 Rust:
polyspec_crudui_validator::text::JsonTextreads the text without replacing anything.validate_text,validate_list_textandvalidate_detail_textrun the validation entries over it, andpolyspec_crudui_generator::textholds the checks of the generation entries.
JSON text is UTF-8. A program that reads a JSON request rejects input that is not UTF-8 as invalid JSON before decoding it.
Shared cases
tests/fixtures/text-validity holds one case
file for each operation, and value-graphs.json, whose cases each runtime that takes shared or
self-containing values builds with its own containers. Byte strings that JSON text cannot carry
are checked by each byte string runtime's own tests.