Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions src/tag/scalar/float_core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,20 @@ const floatCoreTag = defineScalarTag('tag:yaml.org,2002:float', {
// ('.inf'/'.nan' start with '.').
implicitFirstChars: ['-', '+', '.', ...'0123456789'],
resolve: resolveYamlFloat,
identify: (object) => Object.prototype.toString.call(object) === '[object Number]' &&
(object % 1 !== 0 || Object.is(object, -0)),
identify: (object) =>
// No ancient boxed numbers support
typeof object === 'number' &&
(
// We land here all numbers, not handled (declined) by !!int `.identify`
// The same condition as for !!int, but reversed.

// Filter out integers...
!Number.isInteger(object) ||
// but allow negative zero
Object.is(object, -0) ||
// and integers with exponential form
object.toString(10).indexOf('e') >= 0
),
represent: representYamlFloat
})

Expand Down
16 changes: 14 additions & 2 deletions src/tag/scalar/float_json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,20 @@ const floatJsonTag = defineScalarTag('tag:yaml.org,2002:float', {
// Superset of source.charAt(0) over all matched inputs: optional '-' or digit.
implicitFirstChars: ['-', ...'0123456789'],
resolve: resolveYamlFloat,
identify: (object) => Object.prototype.toString.call(object) === '[object Number]' &&
(object % 1 !== 0 || Object.is(object, -0)),
identify: (object) =>
// No ancient boxed numbers support
typeof object === 'number' &&
(
// We land here all numbers, not handled (declined) by !!int `.identify`
// The same condition as for !!int, but reversed.

// Filter out integers...
!Number.isInteger(object) ||
// but allow negative zero
Object.is(object, -0) ||
// and integers with exponential form
object.toString(10).indexOf('e') >= 0
),
represent: representYamlFloat
})

Expand Down
16 changes: 14 additions & 2 deletions src/tag/scalar/float_yaml11.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,20 @@ const floatYaml11Tag = defineScalarTag('tag:yaml.org,2002:float', {
// ('.inf'/'.nan' start with '.').
implicitFirstChars: ['-', '+', '.', ...'0123456789'],
resolve: resolveYamlFloat,
identify: (object) => Object.prototype.toString.call(object) === '[object Number]' &&
(object % 1 !== 0 || Object.is(object, -0)),
identify: (object) =>
// No ancient boxed numbers support
typeof object === 'number' &&
(
// We land here all numbers, not handled (declined) by !!int `.identify`
// The same condition as for !!int, but reversed.

// Filter out integers...
!Number.isInteger(object) ||
// but allow negative zero
Object.is(object, -0) ||
// and integers with exponential form
object.toString(10).indexOf('e') >= 0
),
represent: representYamlFloat
})

Expand Down
9 changes: 7 additions & 2 deletions src/tag/scalar/int_core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,13 @@ const intCoreTag = defineScalarTag('tag:yaml.org,2002:int', {
// Superset of source.charAt(0) over all matched inputs: optional sign + decimal digit.
implicitFirstChars: ['-', '+', ...'0123456789'],
resolve: resolveYamlInteger,
identify: (object) => Object.prototype.toString.call(object) === '[object Number]' &&
(object % 1 === 0 && !Object.is(object, -0)),
identify: (object) =>
// No ancient boxed numbers support
Number.isInteger(object) &&
// Negative zero => !!float
!Object.is(object, -0) &&
// Exponential form => !!float, round-trip for !!int 1e21 will be broken
object.toString(10).indexOf('e') < 0,
represent: (object: number) => object.toString(10)
})

Expand Down
9 changes: 7 additions & 2 deletions src/tag/scalar/int_json.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,13 @@ const intJsonTag = defineScalarTag('tag:yaml.org,2002:int', {
// Superset of source.charAt(0) over all matched inputs: optional '-' or digit.
implicitFirstChars: ['-', ...'0123456789'],
resolve: resolveYamlInteger,
identify: (object) => Object.prototype.toString.call(object) === '[object Number]' &&
(object % 1 === 0 && !Object.is(object, -0)),
identify: (object) =>
// No ancient boxed numbers support
Number.isInteger(object) &&
// Negative zero => !!float
!Object.is(object, -0) &&
// Exponential form => !!float, round-trip for !!int 1e21 will be broken
object.toString(10).indexOf('e') < 0,
represent: (object: number) => object.toString(10)
})

Expand Down
9 changes: 7 additions & 2 deletions src/tag/scalar/int_yaml11.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,13 @@ const intYaml11Tag = defineScalarTag('tag:yaml.org,2002:int', {
// Superset of source.charAt(0) over all matched inputs: optional sign + decimal digit.
implicitFirstChars: ['-', '+', ...'0123456789'],
resolve: resolveYamlInteger,
identify: (object) => Object.prototype.toString.call(object) === '[object Number]' &&
(object % 1 === 0 && !Object.is(object, -0)),
identify: (object) =>
// No ancient boxed numbers support
Number.isInteger(object) &&
// Negative zero => !!float
!Object.is(object, -0) &&
// Exponential form => !!float, round-trip for !!int 1e21 will be broken
object.toString(10).indexOf('e') < 0,
represent: (object: number) => object.toString(10)
})

Expand Down
21 changes: 21 additions & 0 deletions test/core/tags/int.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,27 @@ describe('tags/int', () => {
assert.deepStrictEqual(load(dump(expected, { schema }), { schema }), expected)
})

it(`${name} round-trip of large integers`, () => {
// Integers at or above 1e21 stringify in exponential notation
// ('1e+21'), which is not valid `!!int` text. They must round-trip
// through the float tag rather than being dumped as `!!int '1e+21'`.

// Should round-trip as !!int
assert.strictEqual(dump(1e20, { schema }), '100000000000000000000\n')
assert.strictEqual(load(dump(1e20, { schema }), { schema }), 1e20)
assert.strictEqual(dump(-1e20, { schema }), '-100000000000000000000\n')
assert.strictEqual(load(dump(-1e20, { schema }), { schema }), -1e20)

// Should round-trip as !!float
assert.strictEqual(dump(1e21, { schema }), '1.e+21\n')
assert.strictEqual(load(dump(1e21, { schema }), { schema }), 1e21)
assert.strictEqual(dump(-1e21, { schema }), '-1.e+21\n')
assert.strictEqual(load(dump(-1e21, { schema }), { schema }), -1e21)

assert.strictEqual(load(dump(Number.MAX_VALUE, { schema }), { schema }), Number.MAX_VALUE)
assert.strictEqual(load(dump(-Number.MAX_VALUE, { schema }), { schema }), -Number.MAX_VALUE)
})

it(`${name} fail explicit tag`, () => {
assert.throws(() => load('!!int 1.5', { schema }), /cannot resolve/)
})
Expand Down