typia 14.0.6 → 15.0.1
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.
- package/README.md +3 -0
- package/lib/http.d.ts +49 -24
- package/lib/http.js.map +1 -1
- package/lib/http.mjs.map +1 -1
- package/lib/internal/_createLlmEvaluation.d.ts +1 -0
- package/lib/internal/_createLlmEvaluation.js +486 -0
- package/lib/internal/_createLlmEvaluation.js.map +1 -0
- package/lib/internal/_createLlmEvaluation.mjs +382 -0
- package/lib/internal/_createLlmEvaluation.mjs.map +1 -0
- package/lib/internal/_httpFormDataReadBigint.js +7 -5
- package/lib/internal/_httpFormDataReadBigint.js.map +1 -1
- package/lib/internal/_httpFormDataReadBigint.mjs +1 -1
- package/lib/internal/_httpFormDataReadBigint.mjs.map +1 -1
- package/lib/internal/_httpFormDataReadBoolean.js +12 -10
- package/lib/internal/_httpFormDataReadBoolean.js.map +1 -1
- package/lib/internal/_httpFormDataReadBoolean.mjs +1 -1
- package/lib/internal/_httpFormDataReadBoolean.mjs.map +1 -1
- package/lib/internal/_httpFormDataReadNumber.js +7 -5
- package/lib/internal/_httpFormDataReadNumber.js.map +1 -1
- package/lib/internal/_httpFormDataReadNumber.mjs +1 -1
- package/lib/internal/_httpFormDataReadNumber.mjs.map +1 -1
- package/lib/internal/_httpFormDataReadString.d.ts +9 -1
- package/lib/internal/_httpFormDataReadString.js +10 -2
- package/lib/internal/_httpFormDataReadString.js.map +1 -1
- package/lib/internal/_httpFormDataReadString.mjs +9 -1
- package/lib/internal/_httpFormDataReadString.mjs.map +1 -1
- package/lib/internal/_httpHeaderReadBigint.js +5 -1
- package/lib/internal/_httpHeaderReadBigint.js.map +1 -1
- package/lib/internal/_httpHeaderReadBigint.mjs +2 -1
- package/lib/internal/_httpHeaderReadBigint.mjs.map +1 -1
- package/lib/internal/_httpHeaderReadNumber.js +5 -1
- package/lib/internal/_httpHeaderReadNumber.js.map +1 -1
- package/lib/internal/_httpHeaderReadNumber.mjs +2 -1
- package/lib/internal/_httpHeaderReadNumber.mjs.map +1 -1
- package/lib/internal/_httpParameterReadBigint.js +4 -0
- package/lib/internal/_httpParameterReadBigint.js.map +1 -1
- package/lib/internal/_httpParameterReadBigint.mjs +1 -0
- package/lib/internal/_httpParameterReadBigint.mjs.map +1 -1
- package/lib/internal/_httpParameterReadNumber.js +4 -0
- package/lib/internal/_httpParameterReadNumber.js.map +1 -1
- package/lib/internal/_httpParameterReadNumber.mjs +1 -0
- package/lib/internal/_httpParameterReadNumber.mjs.map +1 -1
- package/lib/internal/_httpParameterReadString.d.ts +9 -1
- package/lib/internal/_httpParameterReadString.js +9 -1
- package/lib/internal/_httpParameterReadString.js.map +1 -1
- package/lib/internal/_httpParameterReadString.mjs +9 -1
- package/lib/internal/_httpParameterReadString.mjs.map +1 -1
- package/lib/internal/_httpQueryReadBigint.js +8 -1
- package/lib/internal/_httpQueryReadBigint.js.map +1 -1
- package/lib/internal/_httpQueryReadBigint.mjs +1 -1
- package/lib/internal/_httpQueryReadBigint.mjs.map +1 -1
- package/lib/internal/_httpQueryReadBoolean.js +4 -1
- package/lib/internal/_httpQueryReadBoolean.js.map +1 -1
- package/lib/internal/_httpQueryReadBoolean.mjs +1 -1
- package/lib/internal/_httpQueryReadBoolean.mjs.map +1 -1
- package/lib/internal/_httpQueryReadNumber.js +8 -1
- package/lib/internal/_httpQueryReadNumber.js.map +1 -1
- package/lib/internal/_httpQueryReadNumber.mjs +1 -1
- package/lib/internal/_httpQueryReadNumber.mjs.map +1 -1
- package/lib/internal/_httpQueryReadString.d.ts +9 -1
- package/lib/internal/_httpQueryReadString.js +9 -1
- package/lib/internal/_httpQueryReadString.js.map +1 -1
- package/lib/internal/_httpQueryReadString.mjs +9 -1
- package/lib/internal/_httpQueryReadString.mjs.map +1 -1
- package/lib/internal/_randomBigint.d.ts +12 -1
- package/lib/internal/_randomBigint.js +90 -2
- package/lib/internal/_randomBigint.js.map +1 -1
- package/lib/internal/_randomBigint.mjs +70 -2
- package/lib/internal/_randomBigint.mjs.map +1 -1
- package/lib/internal/_randomInteger.js +21 -12
- package/lib/internal/_randomInteger.js.map +1 -1
- package/lib/internal/_randomInteger.mjs +21 -16
- package/lib/internal/_randomInteger.mjs.map +1 -1
- package/lib/internal/_randomNumber.js +19 -10
- package/lib/internal/_randomNumber.js.map +1 -1
- package/lib/internal/_randomNumber.mjs +19 -14
- package/lib/internal/_randomNumber.mjs.map +1 -1
- package/lib/internal/_stringLengthGte.d.ts +1 -0
- package/lib/internal/_stringLengthGte.js +14 -0
- package/lib/internal/_stringLengthGte.js.map +1 -0
- package/lib/internal/_stringLengthGte.mjs +11 -0
- package/lib/internal/_stringLengthGte.mjs.map +1 -0
- package/lib/internal/_stringLengthLte.d.ts +1 -0
- package/lib/internal/_stringLengthLte.js +14 -0
- package/lib/internal/_stringLengthLte.js.map +1 -0
- package/lib/internal/_stringLengthLte.mjs +11 -0
- package/lib/internal/_stringLengthLte.mjs.map +1 -0
- package/lib/llm.d.ts +54 -1
- package/lib/llm.js +5 -0
- package/lib/llm.js.map +1 -1
- package/lib/llm.mjs +6 -1
- package/lib/llm.mjs.map +1 -1
- package/lib/re-exports.d.ts +1 -1
- package/lib/re-exports.js.map +1 -1
- package/native/cmd/ttsc-typia/build.go +2 -0
- package/native/cmd/ttsc-typia/dynamic_key_tags_transform_test.go +1 -1
- package/native/cmd/ttsc-typia/llm_evaluation_accepts_property_probability_test.go +27 -0
- package/native/cmd/ttsc-typia/llm_evaluation_accepts_unselected_source_probability_test.go +26 -0
- package/native/cmd/ttsc-typia/llm_evaluation_complete_object_shape_test.go +96 -0
- package/native/cmd/ttsc-typia/llm_evaluation_ignores_declaration_probability_without_call_test.go +18 -0
- package/native/cmd/ttsc-typia/llm_evaluation_plan_emission_transform_test.go +90 -0
- package/native/cmd/ttsc-typia/llm_evaluation_program_scan_dependencies_test.go +69 -0
- package/native/cmd/ttsc-typia/llm_evaluation_rejects_alias_comment_test.go +44 -0
- package/native/cmd/ttsc-typia/llm_evaluation_rejects_alias_refinement_test.go +45 -0
- package/native/cmd/ttsc-typia/llm_evaluation_rejects_computed_method_probability_test.go +30 -0
- package/native/cmd/ttsc-typia/llm_evaluation_rejects_imported_declaration_probability_test.go +48 -0
- package/native/cmd/ttsc-typia/llm_evaluation_rejects_invalid_probability_test.go +208 -0
- package/native/cmd/ttsc-typia/llm_evaluation_rejects_refinements_test.go +94 -0
- package/native/cmd/ttsc-typia/llm_evaluation_rejects_undecidable_types_test.go +232 -0
- package/native/cmd/ttsc-typia/metadata_type_tag_sole_malformed_diagnostic_test.go +94 -0
- package/native/cmd/ttsc-typia/random_recursive_min_items_diagnostic_test.go +18 -1
- package/native/cmd/ttsc-typia/template_literal_type_tags_transform_test.go +3 -2
- package/native/cmd/ttsc-typia/transform.go +2 -0
- package/native/cmd/ttsc-typia/transform_helpers_test.go +17 -3
- package/native/core/context/ITypiaContext.go +4 -0
- package/native/core/factories/ExpressionFactory.go +16 -1
- package/native/core/factories/IdentifierFactory.go +10 -0
- package/native/core/factories/LiteralFactory.go +16 -0
- package/native/core/factories/MetadataCommentTagFactory.go +185 -35
- package/native/core/factories/MetadataTypeTagFactory.go +97 -24
- package/native/core/factories/MetadataTypeTagSchemaFactory.go +5 -0
- package/native/core/factories/expression_factory_number_spells_non_finite_values_test.go +69 -0
- package/native/core/factories/internal/metadata/IMetadataIteratorProps.go +6 -2
- package/native/core/factories/internal/metadata/emplace_metadata_object.go +49 -15
- package/native/core/factories/literal_factory_null_survives_objects_test.go +43 -0
- package/native/core/factories/metadata_comment_tag_factory_holds_bigint_tags_exact_test.go +168 -0
- package/native/core/factories/metadata_comment_tag_factory_reads_javascript_numbers_test.go +158 -0
- package/native/core/factories/metadata_comment_tag_factory_string_length_helpers_test.go +55 -0
- package/native/core/factories/metadata_type_tag_factory_reports_all_invalid_candidates_test.go +73 -0
- package/native/core/programmers/functional/FunctionalAssertParametersProgrammer.go +1 -3
- package/native/core/programmers/functional/FunctionalIsParametersProgrammer.go +107 -9
- package/native/core/programmers/functional/FunctionalValidateParametersProgrammer.go +1 -3
- package/native/core/programmers/http/HttpFormDataProgrammer.go +41 -2
- package/native/core/programmers/http/HttpHeadersProgrammer.go +56 -4
- package/native/core/programmers/http/HttpParameterProgrammer.go +1 -3
- package/native/core/programmers/http/HttpQueryProgrammer.go +26 -43
- package/native/core/programmers/iterate/json_schema_jsDocTags.go +10 -3
- package/native/core/programmers/iterate/json_schema_jsdoc_tags_cast_reads_javascript_numbers_test.go +64 -0
- package/native/core/programmers/llm/LlmApplicationProgrammer.go +1 -0
- package/native/core/programmers/llm/LlmEvaluationProgrammer.go +559 -0
- package/native/core/programmers/llm/LlmParametersProgrammer.go +6 -5
- package/native/core/programmers/llm/LlmReferenceDescription.go +113 -0
- package/native/core/programmers/llm/LlmSchemaProgrammer.go +34 -4
- package/native/core/programmers/llm/llm_reference_description_test.go +134 -0
- package/native/core/schemas/metadata/MetadataDependency.go +9 -0
- package/native/core/utils/NumberUtil.go +195 -0
- package/native/core/utils/number_util_rational_keeps_written_value_test.go +62 -0
- package/native/core/utils/number_util_reads_javascript_number_grammar_test.go +147 -0
- package/native/transform/CallExpressionTransformer.go +1 -0
- package/native/transform/FileTransformer.go +5 -0
- package/native/transform/features/llm/LlmEvaluationProbabilityDeclarations.go +94 -0
- package/native/transform/features/llm/LlmEvaluationProbabilityDeclarations_test.go +50 -0
- package/native/transform/features/llm/LlmEvaluationTransformer.go +59 -0
- package/native/transform/features/llm/LlmSchemaTransformer.go +14 -11
- package/native/transform/features/llm/llm_transformer_entry_coverage_test.go +29 -27
- package/package.json +3 -3
- package/src/http.ts +61 -34
- package/src/internal/_createLlmEvaluation.ts +678 -0
- package/src/internal/_httpFormDataReadBigint.ts +3 -1
- package/src/internal/_httpFormDataReadBoolean.ts +3 -1
- package/src/internal/_httpFormDataReadNumber.ts +3 -1
- package/src/internal/_httpFormDataReadString.ts +10 -1
- package/src/internal/_httpHeaderReadBigint.ts +6 -1
- package/src/internal/_httpHeaderReadNumber.ts +6 -1
- package/src/internal/_httpParameterReadBigint.ts +3 -0
- package/src/internal/_httpParameterReadNumber.ts +3 -0
- package/src/internal/_httpParameterReadString.ts +12 -2
- package/src/internal/_httpQueryReadBigint.ts +7 -1
- package/src/internal/_httpQueryReadBoolean.ts +3 -1
- package/src/internal/_httpQueryReadNumber.ts +7 -1
- package/src/internal/_httpQueryReadString.ts +10 -1
- package/src/internal/_randomBigint.ts +111 -3
- package/src/internal/_randomInteger.ts +31 -16
- package/src/internal/_randomNumber.ts +23 -12
- package/src/internal/_stringLengthGte.ts +6 -0
- package/src/internal/_stringLengthLte.ts +6 -0
- package/src/llm.ts +64 -0
- package/src/re-exports.ts +1 -0
|
@@ -141,7 +141,9 @@ func (metadataTypeTagFactoryNamespace) Analyze(props struct {
|
|
|
141
141
|
}
|
|
142
142
|
}
|
|
143
143
|
if len(filtered) == 0 {
|
|
144
|
-
|
|
144
|
+
// every tag object was malformed: their messages must still be reported,
|
|
145
|
+
// exactly as when a valid tag accompanies them (samchon/typia#2400)
|
|
146
|
+
return metadataTypeTagFactory_flush(props.Errors, props.Type, props.Objects, props.Explore, messages, []schemametadata.IMetadataTypeTag{})
|
|
145
147
|
}
|
|
146
148
|
|
|
147
149
|
tagList := []*metadataTypeTagFactory_ITypeTag{}
|
|
@@ -193,21 +195,35 @@ func (metadataTypeTagFactoryNamespace) Analyze(props struct {
|
|
|
193
195
|
Tags: output,
|
|
194
196
|
})
|
|
195
197
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
198
|
+
return metadataTypeTagFactory_flush(props.Errors, props.Type, props.Objects, props.Explore, messages, output)
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// metadataTypeTagFactory_flush reports the collected tag messages as one
|
|
202
|
+
// error named after the tagged type, and then yields no tags; without
|
|
203
|
+
// messages it yields the analyzed tags.
|
|
204
|
+
func metadataTypeTagFactory_flush(
|
|
205
|
+
errors *[]MetadataFactory_IError,
|
|
206
|
+
typ string,
|
|
207
|
+
objects []*schemametadata.MetadataObjectType,
|
|
208
|
+
explore MetadataFactory_IExplore,
|
|
209
|
+
messages []string,
|
|
210
|
+
output []schemametadata.IMetadataTypeTag,
|
|
211
|
+
) []schemametadata.IMetadataTypeTag {
|
|
212
|
+
if len(messages) == 0 {
|
|
213
|
+
return output
|
|
214
|
+
}
|
|
215
|
+
if errors != nil {
|
|
216
|
+
names := []string{typ}
|
|
217
|
+
for _, object := range objects {
|
|
218
|
+
names = append(names, object.Name)
|
|
207
219
|
}
|
|
208
|
-
|
|
220
|
+
metadataTypeTagFactory_append_error(errors, MetadataFactory_IError{
|
|
221
|
+
Name: strings.Join(names, " & "),
|
|
222
|
+
Explore: explore,
|
|
223
|
+
Messages: messages,
|
|
224
|
+
})
|
|
209
225
|
}
|
|
210
|
-
return
|
|
226
|
+
return []schemametadata.IMetadataTypeTag{}
|
|
211
227
|
}
|
|
212
228
|
|
|
213
229
|
func (metadataTypeTagFactoryNamespace) Validate(props struct {
|
|
@@ -315,12 +331,18 @@ func metadataTypeTagFactory_validate_property(props struct {
|
|
|
315
331
|
Message string
|
|
316
332
|
}{Property: property, Message: "must be a string literal type"})
|
|
317
333
|
}
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
334
|
+
// the value must be one concrete literal shape that the tag schema factory
|
|
335
|
+
// can materialize: a constant, `null`, a tuple of such values, or an object
|
|
336
|
+
// whose content reaches the schema through `schema`. `tags.Default` reads
|
|
337
|
+
// the value back, while `tags.Example` and `tags.Examples` only need the
|
|
338
|
+
// shape to be accepted (samchon/typia#2400, samchon/typia#2403)
|
|
339
|
+
if props.Key == "value" {
|
|
340
|
+
if _, ok := metadataTypeTagFactory_get_value(props.Value); ok == false {
|
|
341
|
+
return props.Report(struct {
|
|
342
|
+
Property *string
|
|
343
|
+
Message string
|
|
344
|
+
}{Property: property, Message: "must be a literal, literal tuple, object, or undefined type"})
|
|
345
|
+
}
|
|
324
346
|
}
|
|
325
347
|
if props.Key == "exclusive" {
|
|
326
348
|
return metadataTypeTagFactory_get_exclusive(struct {
|
|
@@ -344,11 +366,13 @@ func metadataTypeTagFactory_validate_property(props struct {
|
|
|
344
366
|
}
|
|
345
367
|
target := []string{}
|
|
346
368
|
if len(props.Value.Objects) == 0 {
|
|
347
|
-
|
|
369
|
+
// `validate` itself is malformed here, e.g. a template literal built from
|
|
370
|
+
// a non-literal tag value, so name it rather than `target`
|
|
371
|
+
validateProperty := "validate"
|
|
348
372
|
return props.Report(struct {
|
|
349
373
|
Property *string
|
|
350
374
|
Message string
|
|
351
|
-
}{Property: &
|
|
375
|
+
}{Property: &validateProperty, Message: "must be a string literal, or an object whose keys are 'boolean', 'bigint', 'number', 'string', 'array', or 'object'"})
|
|
352
376
|
}
|
|
353
377
|
for _, property := range props.Value.Objects[0].Type.Properties {
|
|
354
378
|
if lit := property.Key.GetSoleLiteral(); lit != nil {
|
|
@@ -415,8 +439,8 @@ func metadataTypeTagFactory_create_metadata_type_tag(props struct {
|
|
|
415
439
|
kind := fmt.Sprint(kindProperty.Value.Constants[0].Values[0].Value)
|
|
416
440
|
|
|
417
441
|
var value any
|
|
418
|
-
if valueProperty := find("value"); valueProperty != nil
|
|
419
|
-
value = valueProperty.Value
|
|
442
|
+
if valueProperty := find("value"); valueProperty != nil {
|
|
443
|
+
value, _ = metadataTypeTagFactory_get_value(valueProperty.Value)
|
|
420
444
|
}
|
|
421
445
|
exclusive := metadataTypeTagFactory_get_exclusive(struct {
|
|
422
446
|
Report func(struct {
|
|
@@ -490,6 +514,55 @@ func metadataTypeTagFactory_create_metadata_type_tag(props struct {
|
|
|
490
514
|
}
|
|
491
515
|
}
|
|
492
516
|
|
|
517
|
+
// metadataTypeTagFactory_get_value reads a tag's `value` as one concrete
|
|
518
|
+
// literal value, and reports whether the metadata names one at all. The
|
|
519
|
+
// accepted shapes mirror what metadataTypeTagSchemaFactory_iterate can
|
|
520
|
+
// materialize: `undefined`, `null`, a single constant, a fixed tuple of such
|
|
521
|
+
// values, or an object. `null` and an object yield a Go nil value; a tuple
|
|
522
|
+
// yields its members in order.
|
|
523
|
+
func metadataTypeTagFactory_get_value(metadata *schemametadata.MetadataSchema) (any, bool) {
|
|
524
|
+
if metadata == nil {
|
|
525
|
+
return nil, false
|
|
526
|
+
}
|
|
527
|
+
if metadata.Size() == 0 {
|
|
528
|
+
// `null` is one literal value; a missing value is the optional `undefined`
|
|
529
|
+
return nil, metadata.Nullable || metadata.IsRequired() == false
|
|
530
|
+
}
|
|
531
|
+
if metadata.Size() != 1 || metadata.Nullable {
|
|
532
|
+
return nil, false
|
|
533
|
+
}
|
|
534
|
+
if len(metadata.Constants) == 1 && len(metadata.Constants[0].Values) == 1 {
|
|
535
|
+
return metadata.Constants[0].Values[0].Value, true
|
|
536
|
+
}
|
|
537
|
+
if metadata.Any || len(metadata.Arrays) != 0 || len(metadata.Atomics) != 0 || len(metadata.Natives) != 0 || len(metadata.Functions) != 0 {
|
|
538
|
+
return nil, false
|
|
539
|
+
}
|
|
540
|
+
if len(metadata.Tuples) == 1 {
|
|
541
|
+
tuple := metadata.Tuples[0].Type
|
|
542
|
+
if tuple.Recursive || tuple.IsRest() {
|
|
543
|
+
return nil, false
|
|
544
|
+
}
|
|
545
|
+
output := make([]any, 0, len(tuple.Elements))
|
|
546
|
+
for _, elem := range tuple.Elements {
|
|
547
|
+
if elem.IsRequired() == false {
|
|
548
|
+
return nil, false
|
|
549
|
+
}
|
|
550
|
+
value, ok := metadataTypeTagFactory_get_value(elem)
|
|
551
|
+
if ok == false {
|
|
552
|
+
return nil, false
|
|
553
|
+
}
|
|
554
|
+
output = append(output, value)
|
|
555
|
+
}
|
|
556
|
+
return output, true
|
|
557
|
+
}
|
|
558
|
+
if len(metadata.Objects) == 1 {
|
|
559
|
+
// Object-valued metadata predates tuple support. Its concrete value is
|
|
560
|
+
// carried by the tag's schema object rather than IMetadataTypeTag.Value.
|
|
561
|
+
return nil, true
|
|
562
|
+
}
|
|
563
|
+
return nil, false
|
|
564
|
+
}
|
|
565
|
+
|
|
493
566
|
func metadataTypeTagFactory_get_exclusive(props struct {
|
|
494
567
|
Report func(struct {
|
|
495
568
|
Property *string
|
|
@@ -33,6 +33,11 @@ func (metadataTypeTagSchemaFactoryNamespace) Object(props struct {
|
|
|
33
33
|
metadata: property.Value,
|
|
34
34
|
})
|
|
35
35
|
if ok {
|
|
36
|
+
// a property literally typed `null` keeps its value; a Go nil would read
|
|
37
|
+
// as absent to every object writer (samchon/typia#2403)
|
|
38
|
+
if value == nil && property.Value.Nullable && property.Value.Size() == 0 {
|
|
39
|
+
value = LiteralFactory_Null{}
|
|
40
|
+
}
|
|
36
41
|
output[*key] = value
|
|
37
42
|
}
|
|
38
43
|
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
package factories
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"math"
|
|
5
|
+
"testing"
|
|
6
|
+
|
|
7
|
+
shimast "github.com/microsoft/typescript-go/shim/ast"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
// TestExpressionFactoryNumberSpellsNonFiniteValues verifies number literals for
|
|
11
|
+
// NaN and the infinities.
|
|
12
|
+
//
|
|
13
|
+
// ExpressionFactory.Number built the literal text with `fmt.Sprint`, which
|
|
14
|
+
// spells positive infinity `+Inf` and prints the magnitude of negative infinity
|
|
15
|
+
// as `Inf`. Both reached the emit as identifiers JavaScript does not declare, so
|
|
16
|
+
// every emitted schema, validator, or random bound carrying one threw
|
|
17
|
+
// `ReferenceError: Inf is not defined` on its first run (samchon/typia#2452).
|
|
18
|
+
// The expected shapes are the JavaScript globals TypeScript's own factory
|
|
19
|
+
// prints. Finite values are the negative twin and must keep their literal.
|
|
20
|
+
//
|
|
21
|
+
// 1. Build numbers for NaN, positive and negative infinity.
|
|
22
|
+
// 2. Assert they are the `NaN` / `Infinity` identifiers, negated for -Infinity.
|
|
23
|
+
// 3. Assert finite values, negative ones, and zero keep numeric literals, with
|
|
24
|
+
// negative zero negated like any negative value rather than spelled `-0`
|
|
25
|
+
// inside one literal.
|
|
26
|
+
func TestExpressionFactoryNumberSpellsNonFiniteValues(t *testing.T) {
|
|
27
|
+
identifier := func(node *shimast.Node, name string) bool {
|
|
28
|
+
return node != nil && node.Kind == shimast.KindIdentifier && node.Text() == name
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if node := ExpressionFactory.Number(math.NaN()); identifier(node, "NaN") == false {
|
|
32
|
+
t.Fatalf("NaN should be the NaN identifier, got kind %v", node.Kind)
|
|
33
|
+
}
|
|
34
|
+
if node := ExpressionFactory.Number(math.Inf(1)); identifier(node, "Infinity") == false {
|
|
35
|
+
t.Fatalf("+Inf should be the Infinity identifier, got kind %v", node.Kind)
|
|
36
|
+
}
|
|
37
|
+
negative := ExpressionFactory.Number(math.Inf(-1))
|
|
38
|
+
if negative.Kind != shimast.KindPrefixUnaryExpression {
|
|
39
|
+
t.Fatalf("-Inf should be a negation, got kind %v", negative.Kind)
|
|
40
|
+
}
|
|
41
|
+
unary := negative.AsPrefixUnaryExpression()
|
|
42
|
+
if unary.Operator != shimast.KindMinusToken || identifier(unary.Operand, "Infinity") == false {
|
|
43
|
+
t.Fatal("-Inf should negate the Infinity identifier")
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
for _, item := range []struct {
|
|
47
|
+
value any
|
|
48
|
+
negative bool
|
|
49
|
+
text string
|
|
50
|
+
}{
|
|
51
|
+
{3, false, "3"},
|
|
52
|
+
{1.5, false, "1.5"},
|
|
53
|
+
{int64(0), false, "0"},
|
|
54
|
+
{-12, true, "12"},
|
|
55
|
+
{-2.5, true, "2.5"},
|
|
56
|
+
{math.Copysign(0, -1), true, "0"},
|
|
57
|
+
} {
|
|
58
|
+
node := ExpressionFactory.Number(item.value)
|
|
59
|
+
if item.negative {
|
|
60
|
+
if node.Kind != shimast.KindPrefixUnaryExpression {
|
|
61
|
+
t.Fatalf("%v should be a negation, got kind %v", item.value, node.Kind)
|
|
62
|
+
}
|
|
63
|
+
node = node.AsPrefixUnaryExpression().Operand
|
|
64
|
+
}
|
|
65
|
+
if node.Kind != shimast.KindNumericLiteral || node.Text() != item.text {
|
|
66
|
+
t.Fatalf("%v should be the numeric literal %q, got kind %v", item.value, item.text, node.Kind)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -14,8 +14,12 @@ type MetadataFactory_IOptions struct {
|
|
|
14
14
|
// method) into the collected properties as function-typed values, without
|
|
15
15
|
// switching on full Functional analysis. Used by the compare programmers to
|
|
16
16
|
// detect user-defined comparison methods.
|
|
17
|
-
Methods
|
|
18
|
-
|
|
17
|
+
Methods bool
|
|
18
|
+
// StrictObjectMembers is for consumers whose emitted value promises to
|
|
19
|
+
// satisfy the entire input type. Include accessors and methods in the
|
|
20
|
+
// structural shape and diagnose members that have no JSON representation.
|
|
21
|
+
StrictObjectMembers bool
|
|
22
|
+
Validate func(props struct {
|
|
19
23
|
Metadata *schemametadata.MetadataSchema
|
|
20
24
|
Explore MetadataFactory_IExplore
|
|
21
25
|
Top *schemametadata.MetadataSchema
|
|
@@ -89,8 +89,40 @@ func Emplace_metadata_object(props IMetadataIteratorProps) *schemametadata.Metad
|
|
|
89
89
|
}
|
|
90
90
|
|
|
91
91
|
isClass := props.Type != nil && props.Type.IsClass()
|
|
92
|
-
isProperty := emplace_metadata_object_significant(props.Options.Functional, props.Options.Methods)
|
|
92
|
+
isProperty := emplace_metadata_object_significant(props.Options.Functional, props.Options.Methods, props.Options.StrictObjectMembers)
|
|
93
|
+
rejectMember := func(name string, message string) {
|
|
94
|
+
if props.Options.StrictObjectMembers == false || props.Errors == nil {
|
|
95
|
+
return
|
|
96
|
+
}
|
|
97
|
+
explore := props.Explore
|
|
98
|
+
explore.Top = false
|
|
99
|
+
explore.Object = obj
|
|
100
|
+
explore.Property = name
|
|
101
|
+
*props.Errors = append(*props.Errors, MetadataFactory_IError{
|
|
102
|
+
Name: obj.Name,
|
|
103
|
+
Explore: explore,
|
|
104
|
+
Messages: []string{message},
|
|
105
|
+
})
|
|
106
|
+
}
|
|
107
|
+
if props.Options.StrictObjectMembers && props.Checker != nil && props.Type != nil {
|
|
108
|
+
if len(props.Checker.GetSignaturesOfType(props.Type, nativechecker.SignatureKindCall)) != 0 {
|
|
109
|
+
rejectMember("[call]", "LLM evaluation does not support callable object types.")
|
|
110
|
+
}
|
|
111
|
+
if len(props.Checker.GetSignaturesOfType(props.Type, nativechecker.SignatureKindConstruct)) != 0 {
|
|
112
|
+
rejectMember("[construct]", "LLM evaluation does not support constructable object types.")
|
|
113
|
+
}
|
|
114
|
+
}
|
|
93
115
|
pred := func(symbol *nativeast.Symbol, node *nativeast.Node) bool {
|
|
116
|
+
name := "<anonymous>"
|
|
117
|
+
if symbol != nil {
|
|
118
|
+
name = symbol.Name
|
|
119
|
+
}
|
|
120
|
+
// Diagnose ES #private before the symbol-key filter so JEV reports the
|
|
121
|
+
// nominal member rather than its compiler-generated mangled name.
|
|
122
|
+
if node != nil && (isClass || props.Options.StrictObjectMembers) && node.Name() != nil && node.Name().Kind == nativeast.KindPrivateIdentifier {
|
|
123
|
+
rejectMember(name, "LLM evaluation does not support private class members.")
|
|
124
|
+
return false
|
|
125
|
+
}
|
|
94
126
|
// A `symbol`-keyed member (`[uniqueSymbol]: T`, `[Symbol.toStringTag]: T`,
|
|
95
127
|
// ...) is not a string / number key: it is unreachable through the string
|
|
96
128
|
// index access typia emits, `JSON.stringify` ignores it, and JSON Schema has
|
|
@@ -104,25 +136,21 @@ func Emplace_metadata_object(props IMetadataIteratorProps) *schemametadata.Metad
|
|
|
104
136
|
// SYMBOL rather than a declaration node so a late-bound member with no
|
|
105
137
|
// reachable declaration is excluded too.
|
|
106
138
|
if symbol != nil && iterate_metadata_intersection_is_symbol_name(symbol.Name) {
|
|
139
|
+
rejectMember(name, "LLM evaluation does not support symbol-keyed properties.")
|
|
107
140
|
return false
|
|
108
141
|
}
|
|
109
142
|
if node == nil {
|
|
110
143
|
return true
|
|
111
144
|
}
|
|
112
|
-
if isClass && node.ModifierFlags()&(nativeast.ModifierFlagsPrivate|nativeast.ModifierFlagsProtected) != 0 {
|
|
145
|
+
if (isClass || props.Options.StrictObjectMembers) && node.ModifierFlags()&(nativeast.ModifierFlagsPrivate|nativeast.ModifierFlagsProtected) != 0 {
|
|
146
|
+
rejectMember(name, "LLM evaluation does not support private or protected class members.")
|
|
113
147
|
return false
|
|
114
148
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
// It is installed only by the constructor and is unreachable via index
|
|
118
|
-
// access, so it is not part of the structural shape; exclude it exactly as a
|
|
119
|
-
// `private`/`protected` keyword member (see ClassNonPublic). ApparentProperties
|
|
120
|
-
// otherwise surfaces it as a mangled key that no runtime object carries, so
|
|
121
|
-
// every real instance would fail its own guard (#2213).
|
|
122
|
-
if isClass && node.Name() != nil && node.Name().Kind == nativeast.KindPrivateIdentifier {
|
|
149
|
+
if isProperty(node) == false {
|
|
150
|
+
rejectMember(name, "LLM evaluation does not support this object member.")
|
|
123
151
|
return false
|
|
124
152
|
}
|
|
125
|
-
return
|
|
153
|
+
return true
|
|
126
154
|
}
|
|
127
155
|
|
|
128
156
|
insert := func(next emplace_metadata_object_insert) *schemametadata.MetadataProperty {
|
|
@@ -135,7 +163,9 @@ func Emplace_metadata_object(props IMetadataIteratorProps) *schemametadata.Metad
|
|
|
135
163
|
}
|
|
136
164
|
|
|
137
165
|
for _, symbol := range props.Components.ApparentProperties(props.Checker, props.Type) {
|
|
138
|
-
|
|
166
|
+
// A complete-shape decoder must see even @internal members so its
|
|
167
|
+
// programmer can reject them; the ordinary structural consumers omit them.
|
|
168
|
+
if metadata_is_internal(symbol) && props.Options.StrictObjectMembers == false {
|
|
139
169
|
continue
|
|
140
170
|
}
|
|
141
171
|
var node *nativeast.Node
|
|
@@ -188,6 +218,7 @@ func Emplace_metadata_object(props IMetadataIteratorProps) *schemametadata.Metad
|
|
|
188
218
|
// intersections so every symbol-only form stays outside typia's structural
|
|
189
219
|
// JSON shape, just like an explicit symbol-keyed member (#2240).
|
|
190
220
|
if emplace_metadata_object_is_symbol_index_key(index.KeyType()) {
|
|
221
|
+
rejectMember("[symbol]", "LLM evaluation does not support symbol-keyed properties.")
|
|
191
222
|
continue
|
|
192
223
|
}
|
|
193
224
|
analyzer := func(typ *nativechecker.Type) func(any) *schemametadata.MetadataSchema {
|
|
@@ -546,7 +577,7 @@ func emplace_metadata_object_intersection_append(
|
|
|
546
577
|
return false
|
|
547
578
|
}
|
|
548
579
|
for _, symbol := range props.Components.ApparentProperties(props.Checker, child) {
|
|
549
|
-
if metadata_is_internal(symbol) {
|
|
580
|
+
if metadata_is_internal(symbol) && props.Options.StrictObjectMembers == false {
|
|
550
581
|
continue
|
|
551
582
|
}
|
|
552
583
|
var node *nativeast.Node
|
|
@@ -652,10 +683,10 @@ func emplace_metadata_object_clone_property(property *schemametadata.MetadataPro
|
|
|
652
683
|
})
|
|
653
684
|
}
|
|
654
685
|
|
|
655
|
-
func emplace_metadata_object_significant(functional bool, methods bool) func(node *nativeast.Node) bool {
|
|
686
|
+
func emplace_metadata_object_significant(functional bool, methods bool, strict bool) func(node *nativeast.Node) bool {
|
|
656
687
|
if functional {
|
|
657
688
|
return func(node *nativeast.Node) bool {
|
|
658
|
-
return node.Kind != nativeast.KindGetAccessor && node.Kind != nativeast.KindSetAccessor
|
|
689
|
+
return strict || (node.Kind != nativeast.KindGetAccessor && node.Kind != nativeast.KindSetAccessor)
|
|
659
690
|
}
|
|
660
691
|
}
|
|
661
692
|
return func(node *nativeast.Node) bool {
|
|
@@ -670,6 +701,9 @@ func emplace_metadata_object_significant(functional bool, methods bool) func(nod
|
|
|
670
701
|
case nativeast.KindMethodDeclaration,
|
|
671
702
|
nativeast.KindMethodSignature:
|
|
672
703
|
return methods
|
|
704
|
+
case nativeast.KindGetAccessor,
|
|
705
|
+
nativeast.KindSetAccessor:
|
|
706
|
+
return strict
|
|
673
707
|
default:
|
|
674
708
|
return false
|
|
675
709
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
package factories
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"encoding/json"
|
|
5
|
+
"testing"
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
// TestLiteralFactoryNullSurvivesObjects verifies an explicit JSON null is kept
|
|
9
|
+
// where a Go nil is dropped.
|
|
10
|
+
//
|
|
11
|
+
// Object writers treat a nil value as absent, so a tag schema holding a real
|
|
12
|
+
// `null` (`tags.Example<null>`) lost it on emission (samchon/typia#2403). The
|
|
13
|
+
// LiteralFactory_Null marker must survive encoding/json, which `typia.reflect`
|
|
14
|
+
// metadata goes through, including inside an ordered object, and must not be
|
|
15
|
+
// classified as nil-like, while a plain nil keeps meaning absent. The printed
|
|
16
|
+
// literal path is covered by `test_json_schema_example_tuple_and_null`.
|
|
17
|
+
//
|
|
18
|
+
// 1. Marshal a map and an ordered object holding the marker and a plain nil.
|
|
19
|
+
// 2. Assert the marker is written as null and the plain nil is omitted where
|
|
20
|
+
// the writer omits it.
|
|
21
|
+
// 3. Assert the marker is not nil-like.
|
|
22
|
+
func TestLiteralFactoryNullSurvivesObjects(t *testing.T) {
|
|
23
|
+
encoded, err := json.Marshal(map[string]any{"example": LiteralFactory_Null{}})
|
|
24
|
+
if err != nil || string(encoded) != `{"example":null}` {
|
|
25
|
+
t.Fatalf("map marker should marshal as null, got %s (%v)", encoded, err)
|
|
26
|
+
}
|
|
27
|
+
ordered, err := json.Marshal(LiteralFactory_OrderedObject{
|
|
28
|
+
Keys: []string{"kept", "absent"},
|
|
29
|
+
Values: map[string]any{
|
|
30
|
+
"kept": LiteralFactory_Null{},
|
|
31
|
+
"absent": nil,
|
|
32
|
+
},
|
|
33
|
+
})
|
|
34
|
+
if err != nil || string(ordered) != `{"kept":null}` {
|
|
35
|
+
t.Fatalf("ordered object should keep the marker and drop nil, got %s (%v)", ordered, err)
|
|
36
|
+
}
|
|
37
|
+
if literalFactory_isNilLike(LiteralFactory_Null{}) {
|
|
38
|
+
t.Fatal("the null marker must not be nil-like")
|
|
39
|
+
}
|
|
40
|
+
if literalFactory_isNilLike(nil) == false {
|
|
41
|
+
t.Fatal("a plain nil must stay nil-like")
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
package factories
|
|
2
|
+
|
|
3
|
+
import (
|
|
4
|
+
"fmt"
|
|
5
|
+
"testing"
|
|
6
|
+
|
|
7
|
+
schemametadata "github.com/samchon/typia/packages/typia/native/core/schemas/metadata"
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
// TestMetadataCommentTagFactoryHoldsBigintTagsExact verifies a numeric comment
|
|
11
|
+
// tag states a bigint bound only when it can state it exactly.
|
|
12
|
+
//
|
|
13
|
+
// The bigint arm of `@minimum`, `@maximum`, `@exclusiveMinimum`,
|
|
14
|
+
// `@exclusiveMaximum`, and `@multipleOf` read its value through a double, so
|
|
15
|
+
// `@minimum 9007199254740993` was enforced as 9007199254740992: the bound
|
|
16
|
+
// validators splice a number literal JavaScript rounds, and `random` drew from
|
|
17
|
+
// the rounded schema while the `@multipleOf` check stayed exact
|
|
18
|
+
// (samchon/typia#2457). Every consumer of the bigint record holds its value as
|
|
19
|
+
// a double, so the record now admits an integer only when a double represents
|
|
20
|
+
// it exactly, within the int64 range of samchon/typia#2352, and splices its
|
|
21
|
+
// exact digits into the bigint check. A number target keeps reading the text
|
|
22
|
+
// as `Number()` does.
|
|
23
|
+
//
|
|
24
|
+
// 1. Admit integers a double represents exactly, whatever their spelling, and
|
|
25
|
+
// splice their exact digits into the bigint check.
|
|
26
|
+
// 2. Refuse every other finite value as a bigint bound: integers a double
|
|
27
|
+
// cannot represent, integers beyond int64, and non-integers, including
|
|
28
|
+
// ones `Number()` rounds to an integer.
|
|
29
|
+
// 3. Report a refused value on a bigint property, and on the bigint part of a
|
|
30
|
+
// `number | bigint` one, while a number property and the number part
|
|
31
|
+
// still take the tag, and report text that is no finite number once.
|
|
32
|
+
func TestMetadataCommentTagFactoryHoldsBigintTagsExact(t *testing.T) {
|
|
33
|
+
//----
|
|
34
|
+
// 1. exact integers
|
|
35
|
+
//----
|
|
36
|
+
for _, item := range []struct {
|
|
37
|
+
text string
|
|
38
|
+
value int64
|
|
39
|
+
}{
|
|
40
|
+
{"9007199254740991", 9007199254740991},
|
|
41
|
+
{"9007199254740992", 9007199254740992},
|
|
42
|
+
{"18014398509481984", 18014398509481984}, // 2^54
|
|
43
|
+
{"54043195528445952", 54043195528445952}, // 3 * 2^54, although `String()` spells it ...950
|
|
44
|
+
{"1152921504606846976", 1152921504606846976}, // 2^60
|
|
45
|
+
{"1.152921504606846976e18", 1152921504606846976},
|
|
46
|
+
{"-9007199254740992", -9007199254740992},
|
|
47
|
+
{"1e3", 1000},
|
|
48
|
+
{"0x10", 16},
|
|
49
|
+
{"-0", 0},
|
|
50
|
+
{"0e999999999", 0},
|
|
51
|
+
{"0E5", 0},
|
|
52
|
+
{"0e99999999999999999999", 0}, // an exponent `big.Rat` cannot parse
|
|
53
|
+
{"0x0", 0},
|
|
54
|
+
{"10000000000000000", 10000000000000000},
|
|
55
|
+
} {
|
|
56
|
+
value, numeric, ok := metadataCommentTagFactory_bigint(item.text)
|
|
57
|
+
if ok == false || numeric == false || value != item.value {
|
|
58
|
+
t.Fatalf("%s must be the bigint %d, got %d (numeric=%v ok=%v)", item.text, item.value, value, numeric, ok)
|
|
59
|
+
}
|
|
60
|
+
if spliced := metadataCommentTagFactory_splice_integer(item.text); spliced != fmt.Sprint(item.value) {
|
|
61
|
+
t.Fatalf("%s must splice into a bigint check as %d, got %s", item.text, item.value, spliced)
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
//----
|
|
66
|
+
// 2. finite values no bigint tag states, and text that is no number
|
|
67
|
+
//----
|
|
68
|
+
for _, text := range []string{
|
|
69
|
+
"9007199254740993", // rounds to ...992
|
|
70
|
+
"9007199254740993.0", // the same integer, spelled with a point
|
|
71
|
+
"9.007199254740993e15", // and with an exponent
|
|
72
|
+
"-9007199254740993",
|
|
73
|
+
"0x20000000000001", // 2^53 + 1 in hexadecimal
|
|
74
|
+
"1152921504606847000", // `String(2 ** 60)`, which is not 2^60
|
|
75
|
+
"10000000000000000000", // beyond int64
|
|
76
|
+
"1.5",
|
|
77
|
+
"1e-3",
|
|
78
|
+
"5.0000000000000001", // `Number()` reads 5
|
|
79
|
+
"1e-400", // `Number()` reads 0
|
|
80
|
+
"1e-1000001", // underflows to 0, but writes no zero
|
|
81
|
+
} {
|
|
82
|
+
if _, numeric, ok := metadataCommentTagFactory_bigint(text); ok || numeric == false {
|
|
83
|
+
t.Fatalf("%s must be a finite value no bigint tag states (numeric=%v ok=%v)", text, numeric, ok)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
for _, text := range []string{"Infinity", "abc", "1_000"} {
|
|
87
|
+
if _, numeric, ok := metadataCommentTagFactory_bigint(text); ok || numeric {
|
|
88
|
+
t.Fatalf("%s is no finite number (numeric=%v ok=%v)", text, numeric, ok)
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
//----
|
|
93
|
+
// 3. where the refusal is reported
|
|
94
|
+
//----
|
|
95
|
+
analyze := func(types []string, name string, text string) (*schemametadata.MetadataSchema, []string) {
|
|
96
|
+
atomics := []*schemametadata.MetadataAtomic{}
|
|
97
|
+
for _, typ := range types {
|
|
98
|
+
atomics = append(atomics, schemametadata.MetadataAtomic_create(schemametadata.MetadataAtomic{Type: typ}))
|
|
99
|
+
}
|
|
100
|
+
meta := schemametadata.MetadataSchema_create(schemametadata.MetadataSchema{Atomics: atomics})
|
|
101
|
+
errors := []MetadataFactory_IError{}
|
|
102
|
+
MetadataCommentTagFactory.Analyze(struct {
|
|
103
|
+
Errors *[]MetadataFactory_IError
|
|
104
|
+
Metadata *schemametadata.MetadataSchema
|
|
105
|
+
Tags []schemametadata.IJsDocTagInfo
|
|
106
|
+
Explore MetadataFactory_IExplore
|
|
107
|
+
}{
|
|
108
|
+
Errors: &errors,
|
|
109
|
+
Metadata: meta,
|
|
110
|
+
Tags: []schemametadata.IJsDocTagInfo{{Name: name, Text: []schemametadata.IJsDocTagInfo_IText{{Text: text}}}},
|
|
111
|
+
})
|
|
112
|
+
messages := []string{}
|
|
113
|
+
for _, err := range errors {
|
|
114
|
+
messages = append(messages, err.Messages...)
|
|
115
|
+
}
|
|
116
|
+
return meta, messages
|
|
117
|
+
}
|
|
118
|
+
refusal := "bigint value 9007199254740993 is not an int64 integer that a number represents exactly"
|
|
119
|
+
for _, name := range []string{"minimum", "maximum", "exclusiveMinimum", "exclusiveMaximum", "multipleOf"} {
|
|
120
|
+
if _, messages := analyze([]string{"bigint"}, name, "9007199254740993"); len(messages) != 1 || messages[0] != refusal {
|
|
121
|
+
t.Fatalf("@%s on a bigint must report the refusal alone, got %#v", name, messages)
|
|
122
|
+
}
|
|
123
|
+
meta, messages := analyze([]string{"number"}, name, "9007199254740993")
|
|
124
|
+
if len(messages) != 0 || len(meta.Atomics[0].Tags) != 1 {
|
|
125
|
+
t.Fatalf("@%s on a number must apply, got %#v", name, messages)
|
|
126
|
+
}
|
|
127
|
+
meta, messages = analyze([]string{"number", "bigint"}, name, "9007199254740993")
|
|
128
|
+
if len(messages) != 1 || messages[0] != refusal {
|
|
129
|
+
t.Fatalf("@%s on number | bigint must report the bigint part, got %#v", name, messages)
|
|
130
|
+
}
|
|
131
|
+
if len(meta.Atomics[0].Tags) != 1 || len(meta.Atomics[1].Tags) != 0 {
|
|
132
|
+
t.Fatalf("@%s on number | bigint must constrain the number part only", name)
|
|
133
|
+
}
|
|
134
|
+
if meta, messages := analyze([]string{"bigint"}, name, "9007199254740992"); len(messages) != 0 || len(meta.Atomics[0].Tags) != 1 {
|
|
135
|
+
t.Fatalf("@%s 9007199254740992 on a bigint must apply, got %#v", name, messages)
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// A value `Number()` rounds to an integer still names no bigint bound: the
|
|
139
|
+
// number part takes it as 5, and the bigint part is reported, not dropped.
|
|
140
|
+
meta, messages := analyze([]string{"number", "bigint"}, "minimum", "5.0000000000000001")
|
|
141
|
+
if len(messages) != 1 || messages[0] != "bigint value 5.0000000000000001 is not an int64 integer that a number represents exactly" {
|
|
142
|
+
t.Fatalf("@minimum 5.0000000000000001 on number | bigint must report the bigint part, got %#v", messages)
|
|
143
|
+
}
|
|
144
|
+
if len(meta.Atomics[0].Tags) != 1 || meta.Atomics[0].Tags[0][0].Validate != "5 <= $input" || len(meta.Atomics[1].Tags) != 0 {
|
|
145
|
+
t.Fatal("@minimum 5.0000000000000001 on number | bigint must constrain the number part only")
|
|
146
|
+
}
|
|
147
|
+
if _, messages := analyze([]string{"bigint"}, "minimum", "1.5"); len(messages) != 1 || messages[0] != "bigint value 1.5 is not an int64 integer that a number represents exactly" {
|
|
148
|
+
t.Fatalf("@minimum 1.5 on a bigint must be refused, got %#v", messages)
|
|
149
|
+
}
|
|
150
|
+
if _, messages := analyze([]string{"number", "bigint"}, "minimum", "1e-1000001"); len(messages) != 1 || messages[0] != "bigint value 1e-1000001 is not an int64 integer that a number represents exactly" {
|
|
151
|
+
t.Fatalf("@minimum 1e-1000001 on number | bigint must report the bigint part, got %#v", messages)
|
|
152
|
+
}
|
|
153
|
+
// Text that is no finite number is reported once, as such, on any target.
|
|
154
|
+
for _, item := range []struct {
|
|
155
|
+
text string
|
|
156
|
+
message string
|
|
157
|
+
}{
|
|
158
|
+
{"abc", "invalid number"},
|
|
159
|
+
{"Infinity", "non-finite number"},
|
|
160
|
+
{"1e400", "non-finite number"},
|
|
161
|
+
} {
|
|
162
|
+
for _, types := range [][]string{{"bigint"}, {"number", "bigint"}} {
|
|
163
|
+
if _, messages := analyze(types, "minimum", item.text); len(messages) != 1 || messages[0] != item.message {
|
|
164
|
+
t.Fatalf("@minimum %s on %v must report %q alone, got %#v", item.text, types, item.message, messages)
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|