From 8cea38077d1f0fd3ffec197c76cf7873b8d321e2 Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Thu, 19 Aug 2021 21:41:32 +0200 Subject: [PATCH 1/5] fix(custom-elements): cast numbers with Number rules Fix #4370 --- .../__tests__/apiCustomElement.spec.ts | 36 +++++++++++++++++++ packages/runtime-dom/src/apiCustomElement.ts | 9 ++++- 2 files changed, 44 insertions(+), 1 deletion(-) create mode 100644 packages/runtime-dom/__tests__/apiCustomElement.spec.ts diff --git a/packages/runtime-dom/__tests__/apiCustomElement.spec.ts b/packages/runtime-dom/__tests__/apiCustomElement.spec.ts new file mode 100644 index 00000000000..accd1d38d07 --- /dev/null +++ b/packages/runtime-dom/__tests__/apiCustomElement.spec.ts @@ -0,0 +1,36 @@ +import { toNumber } from '../src/apiCustomElement' + +describe('Custom Element', () => { + describe('toNumber', () => { + it('handles strings', () => { + expect(toNumber('')).toBe('') + expect(toNumber(null)).toBe('') + expect(toNumber('Something else')).toBe('Something else') + }) + + it('numbers', () => { + expect(toNumber('0')).toBe(0) + expect(toNumber('1')).toBe(1) + expect(toNumber('1.1')).toBe(1.1) + expect(toNumber('123e-1')).toBe(12.3) + expect(toNumber('Infinity')).toBe(Infinity) + }) + + it('NaN', () => { + expect(toNumber('NaN')).toBeNaN() + expect(toNumber('nan')).not.toBeNaN() + }) + + // all of these are handled by Number + it('string non decimal bases', () => { + expect(toNumber('0b0')).toBe(0) + expect(toNumber('0b1')).toBe(1) + + expect(toNumber('0o3')).toBe(3) + expect(toNumber('0o0')).toBe(0) + + expect(toNumber('0x0')).toBe(0) + expect(toNumber('0xf')).toBe(15) + }) + }) +}) diff --git a/packages/runtime-dom/src/apiCustomElement.ts b/packages/runtime-dom/src/apiCustomElement.ts index ca29a436c72..bbea883ef4c 100644 --- a/packages/runtime-dom/src/apiCustomElement.ts +++ b/packages/runtime-dom/src/apiCustomElement.ts @@ -21,7 +21,7 @@ import { ConcreteComponent, ComponentOptions } from '@vue/runtime-core' -import { camelize, extend, hyphenate, isArray, toNumber } from '@vue/shared' +import { camelize, extend, hyphenate, isArray } from '@vue/shared' import { hydrate, render } from '.' export type VueElementConstructor

= { @@ -342,3 +342,10 @@ export class VueElement extends BaseClass { } } } + +export function toNumber(value: string | null): number | string { + // for Number('') and Number(null) as they both become 0 + if (!value) return '' + const casted = Number(value) + return value === 'NaN' || !Number.isNaN(casted) ? casted : value +} From e7b393bfef712c3588654d1c55b81859e521e1aa Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Fri, 20 Aug 2021 11:45:06 +0200 Subject: [PATCH 2/5] chore: rename --- .../__tests__/apiCustomElement.spec.ts | 36 +++++++++---------- packages/runtime-dom/src/apiCustomElement.ts | 4 +-- 2 files changed, 20 insertions(+), 20 deletions(-) diff --git a/packages/runtime-dom/__tests__/apiCustomElement.spec.ts b/packages/runtime-dom/__tests__/apiCustomElement.spec.ts index accd1d38d07..96fb6dfe7d3 100644 --- a/packages/runtime-dom/__tests__/apiCustomElement.spec.ts +++ b/packages/runtime-dom/__tests__/apiCustomElement.spec.ts @@ -1,36 +1,36 @@ -import { toNumber } from '../src/apiCustomElement' +import { parseNumber } from '../src/apiCustomElement' describe('Custom Element', () => { - describe('toNumber', () => { + describe('parseNumber', () => { it('handles strings', () => { - expect(toNumber('')).toBe('') - expect(toNumber(null)).toBe('') - expect(toNumber('Something else')).toBe('Something else') + expect(parseNumber('')).toBe('') + expect(parseNumber(null)).toBe('') + expect(parseNumber('Something else')).toBe('Something else') }) it('numbers', () => { - expect(toNumber('0')).toBe(0) - expect(toNumber('1')).toBe(1) - expect(toNumber('1.1')).toBe(1.1) - expect(toNumber('123e-1')).toBe(12.3) - expect(toNumber('Infinity')).toBe(Infinity) + expect(parseNumber('0')).toBe(0) + expect(parseNumber('1')).toBe(1) + expect(parseNumber('1.1')).toBe(1.1) + expect(parseNumber('123e-1')).toBe(12.3) + expect(parseNumber('Infinity')).toBe(Infinity) }) it('NaN', () => { - expect(toNumber('NaN')).toBeNaN() - expect(toNumber('nan')).not.toBeNaN() + expect(parseNumber('NaN')).toBeNaN() + expect(parseNumber('nan')).not.toBeNaN() }) // all of these are handled by Number it('string non decimal bases', () => { - expect(toNumber('0b0')).toBe(0) - expect(toNumber('0b1')).toBe(1) + expect(parseNumber('0b0')).toBe(0) + expect(parseNumber('0b1')).toBe(1) - expect(toNumber('0o3')).toBe(3) - expect(toNumber('0o0')).toBe(0) + expect(parseNumber('0o3')).toBe(3) + expect(parseNumber('0o0')).toBe(0) - expect(toNumber('0x0')).toBe(0) - expect(toNumber('0xf')).toBe(15) + expect(parseNumber('0x0')).toBe(0) + expect(parseNumber('0xf')).toBe(15) }) }) }) diff --git a/packages/runtime-dom/src/apiCustomElement.ts b/packages/runtime-dom/src/apiCustomElement.ts index bbea883ef4c..f43d75deea8 100644 --- a/packages/runtime-dom/src/apiCustomElement.ts +++ b/packages/runtime-dom/src/apiCustomElement.ts @@ -246,7 +246,7 @@ export class VueElement extends BaseClass { } protected _setAttr(key: string) { - this._setProp(camelize(key), toNumber(this.getAttribute(key)), false) + this._setProp(camelize(key), parseNumber(this.getAttribute(key)), false) } /** @@ -343,7 +343,7 @@ export class VueElement extends BaseClass { } } -export function toNumber(value: string | null): number | string { +export function parseNumber(value: string | null): number | string { // for Number('') and Number(null) as they both become 0 if (!value) return '' const casted = Number(value) From 2dcaf04e917f0cd3e0cfe10f3a168edfc2155d6a Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Tue, 24 Aug 2021 10:17:49 +0200 Subject: [PATCH 3/5] refactor: move test --- .../__tests__/customElement.spec.ts | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/packages/runtime-dom/__tests__/customElement.spec.ts b/packages/runtime-dom/__tests__/customElement.spec.ts index 042ac68a7af..2bd0ada28ae 100644 --- a/packages/runtime-dom/__tests__/customElement.spec.ts +++ b/packages/runtime-dom/__tests__/customElement.spec.ts @@ -9,6 +9,7 @@ import { renderSlot, VueElement } from '../src' +import { toNumber } from '../src/apiCustomElement' describe('defineCustomElement', () => { const container = document.createElement('div') @@ -394,3 +395,36 @@ describe('defineCustomElement', () => { }) }) }) + +describe('toNumber', () => { + it('handles strings', () => { + expect(toNumber('')).toBe('') + expect(toNumber(null)).toBe('') + expect(toNumber('Something else')).toBe('Something else') + }) + + it('numbers', () => { + expect(toNumber('0')).toBe(0) + expect(toNumber('1')).toBe(1) + expect(toNumber('1.1')).toBe(1.1) + expect(toNumber('123e-1')).toBe(12.3) + expect(toNumber('Infinity')).toBe(Infinity) + }) + + it('NaN', () => { + expect(toNumber('NaN')).toBeNaN() + expect(toNumber('nan')).not.toBeNaN() + }) + + // all of these are handled by Number + it('string non decimal bases', () => { + expect(toNumber('0b0')).toBe(0) + expect(toNumber('0b1')).toBe(1) + + expect(toNumber('0o3')).toBe(3) + expect(toNumber('0o0')).toBe(0) + + expect(toNumber('0x0')).toBe(0) + expect(toNumber('0xf')).toBe(15) + }) +}) From 2e5b2a70c3e76d5dc05dcbd709889a405159b098 Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Tue, 24 Aug 2021 10:19:26 +0200 Subject: [PATCH 4/5] refactor: rename --- .../__tests__/customElement.spec.ts | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/runtime-dom/__tests__/customElement.spec.ts b/packages/runtime-dom/__tests__/customElement.spec.ts index 2bd0ada28ae..e56482c6174 100644 --- a/packages/runtime-dom/__tests__/customElement.spec.ts +++ b/packages/runtime-dom/__tests__/customElement.spec.ts @@ -9,7 +9,7 @@ import { renderSlot, VueElement } from '../src' -import { toNumber } from '../src/apiCustomElement' +import { parseNumber } from '../src/apiCustomElement' describe('defineCustomElement', () => { const container = document.createElement('div') @@ -396,35 +396,35 @@ describe('defineCustomElement', () => { }) }) -describe('toNumber', () => { +describe('parseNumber', () => { it('handles strings', () => { - expect(toNumber('')).toBe('') - expect(toNumber(null)).toBe('') - expect(toNumber('Something else')).toBe('Something else') + expect(parseNumber('')).toBe('') + expect(parseNumber(null)).toBe('') + expect(parseNumber('Something else')).toBe('Something else') }) it('numbers', () => { - expect(toNumber('0')).toBe(0) - expect(toNumber('1')).toBe(1) - expect(toNumber('1.1')).toBe(1.1) - expect(toNumber('123e-1')).toBe(12.3) - expect(toNumber('Infinity')).toBe(Infinity) + expect(parseNumber('0')).toBe(0) + expect(parseNumber('1')).toBe(1) + expect(parseNumber('1.1')).toBe(1.1) + expect(parseNumber('123e-1')).toBe(12.3) + expect(parseNumber('Infinity')).toBe(Infinity) }) it('NaN', () => { - expect(toNumber('NaN')).toBeNaN() - expect(toNumber('nan')).not.toBeNaN() + expect(parseNumber('NaN')).toBeNaN() + expect(parseNumber('nan')).not.toBeNaN() }) // all of these are handled by Number it('string non decimal bases', () => { - expect(toNumber('0b0')).toBe(0) - expect(toNumber('0b1')).toBe(1) + expect(parseNumber('0b0')).toBe(0) + expect(parseNumber('0b1')).toBe(1) - expect(toNumber('0o3')).toBe(3) - expect(toNumber('0o0')).toBe(0) + expect(parseNumber('0o3')).toBe(3) + expect(parseNumber('0o0')).toBe(0) - expect(toNumber('0x0')).toBe(0) - expect(toNumber('0xf')).toBe(15) + expect(parseNumber('0x0')).toBe(0) + expect(parseNumber('0xf')).toBe(15) }) }) From 1b85df2350acb1269501d48947c9e2267d980284 Mon Sep 17 00:00:00 2001 From: Eduardo San Martin Morote Date: Tue, 24 Aug 2021 10:20:45 +0200 Subject: [PATCH 5/5] chore: remove file again --- .../__tests__/apiCustomElement.spec.ts | 36 ------------------- 1 file changed, 36 deletions(-) delete mode 100644 packages/runtime-dom/__tests__/apiCustomElement.spec.ts diff --git a/packages/runtime-dom/__tests__/apiCustomElement.spec.ts b/packages/runtime-dom/__tests__/apiCustomElement.spec.ts deleted file mode 100644 index 96fb6dfe7d3..00000000000 --- a/packages/runtime-dom/__tests__/apiCustomElement.spec.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { parseNumber } from '../src/apiCustomElement' - -describe('Custom Element', () => { - describe('parseNumber', () => { - it('handles strings', () => { - expect(parseNumber('')).toBe('') - expect(parseNumber(null)).toBe('') - expect(parseNumber('Something else')).toBe('Something else') - }) - - it('numbers', () => { - expect(parseNumber('0')).toBe(0) - expect(parseNumber('1')).toBe(1) - expect(parseNumber('1.1')).toBe(1.1) - expect(parseNumber('123e-1')).toBe(12.3) - expect(parseNumber('Infinity')).toBe(Infinity) - }) - - it('NaN', () => { - expect(parseNumber('NaN')).toBeNaN() - expect(parseNumber('nan')).not.toBeNaN() - }) - - // all of these are handled by Number - it('string non decimal bases', () => { - expect(parseNumber('0b0')).toBe(0) - expect(parseNumber('0b1')).toBe(1) - - expect(parseNumber('0o3')).toBe(3) - expect(parseNumber('0o0')).toBe(0) - - expect(parseNumber('0x0')).toBe(0) - expect(parseNumber('0xf')).toBe(15) - }) - }) -})