diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 0000000..25c9bac --- /dev/null +++ b/jest.config.js @@ -0,0 +1,3 @@ +module.exports = { + testEnvironment: 'node', +}; diff --git a/package.json b/package.json index da30d9a..7b3a842 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,9 @@ ], "devDependencies": { "@size-limit/preset-small-lib": "^4.10.2", + "@types/jsdom": "^16.2.10", "husky": "^6.0.0", + "jsdom": "^16.5.3", "size-limit": "^4.10.2", "tsdx": "^0.14.1", "tslib": "^2.2.0", diff --git a/src/index.test.ts b/src/index.test.ts new file mode 100644 index 0000000..337186f --- /dev/null +++ b/src/index.test.ts @@ -0,0 +1,89 @@ +import * as fixtures from '../test/fixtures' +import getFormValues from '.' + +describe('blank template', () => { + let window: fixtures.Window + beforeEach(async () => { + window = await fixtures.loadTemplate('blank') + }) + it('should have blank form value', () => { + const [form] = Array.from(window.document.getElementsByTagName('form')) + const values = getFormValues(form) + expect(values).toEqual({}) + }) +}) + +describe('single input template', () => { + let window: fixtures.Window + beforeEach(async () => { + window = await fixtures.loadTemplate('single-input') + }) + it('should have a single form value', () => { + const [form] = Array.from(window.document.getElementsByTagName('form')) + const values = getFormValues(form) + expect(values).toEqual({ hello: 'Hi' }) + }) +}) + +describe('single disabled input template', () => { + let window: fixtures.Window + beforeEach(async () => { + window = await fixtures.loadTemplate('single-disabled-input') + }) + it('should have blank form value', () => { + const [form] = Array.from(window.document.getElementsByTagName('form')) + const values = getFormValues(form) + expect(values).toEqual({}) + }) +}) + +describe('single readonly input template', () => { + let window: fixtures.Window + beforeEach(async () => { + window = await fixtures.loadTemplate('single-readonly-input') + }) + it('should have a single form value', () => { + const [form] = Array.from(window.document.getElementsByTagName('form')) + const values = getFormValues(form) + expect(values).toEqual({ hello: 'Hi' }) + }) +}) + +describe('single input with double submitters template', () => { + let window: fixtures.Window + beforeEach(async () => { + window = await fixtures.loadTemplate('single-input-with-double-submitters') + }) + it('should have a single form value', () => { + const [form] = Array.from(window.document.getElementsByTagName('form')) + const values = getFormValues(form) + expect(values).toEqual({ hello: 'Hi' }) + }) + + it('should include the submitter\'s value when provided', () => { + const [form] = Array.from(window.document.getElementsByTagName('form')) + const [submitter] = Array.from(window.document.getElementsByTagName('button')) + const values = getFormValues(form, submitter) + expect(values).toEqual({ hello: 'Hi', [submitter.name]: submitter.value }) + }) +}) + +describe('single input with double input submitters template', () => { + let window: fixtures.Window + beforeEach(async () => { + window = await fixtures.loadTemplate('single-input-with-double-input-submitters') + }) + + it('should have a single form value', () => { + const [form] = Array.from(window.document.getElementsByTagName('form')) + const values = getFormValues(form) + expect(values).toEqual({ hello: 'Hi' }) + }) + + it('should include the submitter\'s value when provided', () => { + const [form] = Array.from(window.document.getElementsByTagName('form')) + const [,submitter] = Array.from(window.document.getElementsByTagName('input')).filter(i => i.type === 'submit') + const values = getFormValues(form, submitter) + expect(values).toEqual({ hello: 'Hi', [submitter.name]: submitter.value }) + }) +}) diff --git a/src/index.ts b/src/index.ts index 5f808e8..1953544 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,8 @@ +const RadioNodeList = global.RadioNodeList || class RadioNodeList { + name: string = '' + disabled: boolean = false +} + type HTMLFieldElement = HTMLInputElement | HTMLButtonElement @@ -5,7 +10,7 @@ type HTMLFieldElement | HTMLTextAreaElement type FieldNode - = RadioNodeList + = typeof RadioNodeList | HTMLFieldElement type HTMLSubmitterElement @@ -17,19 +22,22 @@ const isFormFieldElement = (el: FieldNode) => { return true } const htmlEl = el as HTMLElement - const tagName = htmlEl.tagName.toLowerCase() - if (['SELECT', 'TEXTAREA', 'BUTTON'].includes(tagName)) { + const tagName = htmlEl.tagName + if (['SELECT', 'TEXTAREA'].includes(tagName)) { return true } if (tagName !== 'INPUT') { return false } const inputEl = htmlEl as HTMLInputElement - const type = inputEl.type.toLowerCase() + const type = inputEl.type const checkedValue = inputEl.getAttribute('value') if (type === 'checkbox' && checkedValue !== null) { return inputEl.checked } + if (type === 'submit' || type === 'reset') { + return false + } return Boolean(inputEl.name) } @@ -95,17 +103,17 @@ const getRadioNodeListResolvedValue = (radioNodeList: RadioNodeList, submitter?: */ const getFieldValue = (el: FieldNode, submitter?: HTMLSubmitterElement) => { if ((el as unknown) instanceof RadioNodeList) { - return getRadioNodeListResolvedValue(el as RadioNodeList, submitter) + return getRadioNodeListResolvedValue(el as unknown as RadioNodeList, submitter) } const fieldEl = el as HTMLFieldElement const tagName = fieldEl.tagName - const type = fieldEl.type.toLowerCase() + const type = fieldEl.type if (tagName === 'SELECT' && fieldEl.value === '') { return null } - if (tagName === 'INPUT' && type === 'CHECKBOX') { + if (tagName === 'INPUT' && type === 'checkbox') { const inputFieldEl = fieldEl as HTMLInputElement const checkedValue = inputFieldEl.getAttribute('value') if (checkedValue !== null) { @@ -122,38 +130,47 @@ const getFieldValue = (el: FieldNode, submitter?: HTMLSubmitterElement) => { /** * Returns only named form field elements. - * @param key - The key from the `form.elements` object. * @param el - The element */ -const isValidFormField = (key: string, el: FieldNode) => { +const isValidFormField = (el: FieldNode) => { return ( - isNaN(Number(key)) + 'name' in el + && typeof el['name'] === 'string' + && el['name'].length > 0 + && !('disabled' in el && Boolean(el['disabled'])) && isFormFieldElement(el) ) } -// TODO handle disabled/readonly fields /** * Gets the values of all the fields within the form through accessing the DOM nodes. - * @param form - The form element. - * @param submitter - The element which triggered the form's submit event. */ const getFormValues = (form: HTMLFormElement, submitter?: HTMLSubmitterElement) => { + if (!form) { + throw new TypeError('Invalid form element.') + } const formElements = form.elements as unknown as Record const allFormFieldElements = Object.entries(formElements) - const formFieldElements = allFormFieldElements.filter(([key, el]) => isValidFormField(key, el)) - return formFieldElements.reduce( - (theFormValues, [name, el]) => { + const formFieldElements = allFormFieldElements.filter(([, el]) => isValidFormField(el)) + const fieldValues = formFieldElements.reduce( + (theFormValues, [,el]) => { const fieldValue = getFieldValue(el, submitter) if (fieldValue === null) { return theFormValues } return { - [name]: fieldValue, + [el['name'] as string]: fieldValue, } }, {} ) + if (Boolean(submitter as unknown)) { + return { + ...fieldValues, + [(submitter as HTMLSubmitterElement).name]: (submitter as HTMLSubmitterElement).value, + } + } + return fieldValues } export default getFormValues diff --git a/test/blah.test.ts b/test/blah.test.ts deleted file mode 100644 index e69de29..0000000 diff --git a/test/fixtures/index.ts b/test/fixtures/index.ts new file mode 100644 index 0000000..2ad18f4 --- /dev/null +++ b/test/fixtures/index.ts @@ -0,0 +1,11 @@ +import fs from 'fs' +import path from 'path' +import {DOMWindow, JSDOM} from 'jsdom' + +export type Window = DOMWindow + +export const loadTemplate = async (templateName: string): Promise => { + const templatePath = path.join('test', 'fixtures', 'templates', `${templateName}.html`) + const templateRaw = await fs.promises.readFile(templatePath) + return new JSDOM(templateRaw.toString('utf-8')).window +} diff --git a/test/fixtures/templates/blank.html b/test/fixtures/templates/blank.html new file mode 100644 index 0000000..e54c614 --- /dev/null +++ b/test/fixtures/templates/blank.html @@ -0,0 +1,10 @@ + + + + + Title + + +
+ + diff --git a/test/fixtures/templates/default.html b/test/fixtures/templates/default.html new file mode 100644 index 0000000..652bb4e --- /dev/null +++ b/test/fixtures/templates/default.html @@ -0,0 +1,84 @@ + + + + + Title + + +
+

+
+
+ +
+
+ +
+
+ +
+
+ Gender +
+ + +
+
+
+ +
+
+ +
+
+ +
+
+ + Default Dependents + +
+ + +
+
+
+ +
+
+ +
+
+ + +
+
+
+ + diff --git a/test/fixtures/templates/single-disabled-input.html b/test/fixtures/templates/single-disabled-input.html new file mode 100644 index 0000000..135df30 --- /dev/null +++ b/test/fixtures/templates/single-disabled-input.html @@ -0,0 +1,19 @@ + + + + + Title + + +
+ + +
+ + diff --git a/test/fixtures/templates/single-input-with-double-input-submitters.html b/test/fixtures/templates/single-input-with-double-input-submitters.html new file mode 100644 index 0000000..c25fa20 --- /dev/null +++ b/test/fixtures/templates/single-input-with-double-input-submitters.html @@ -0,0 +1,17 @@ + + + + + Title + + +
+ + + +
+ + diff --git a/test/fixtures/templates/single-input-with-double-submitters.html b/test/fixtures/templates/single-input-with-double-submitters.html new file mode 100644 index 0000000..d70293e --- /dev/null +++ b/test/fixtures/templates/single-input-with-double-submitters.html @@ -0,0 +1,17 @@ + + + + + Title + + +
+ + + +
+ + diff --git a/test/fixtures/templates/single-input.html b/test/fixtures/templates/single-input.html new file mode 100644 index 0000000..01adf54 --- /dev/null +++ b/test/fixtures/templates/single-input.html @@ -0,0 +1,16 @@ + + + + + Title + + +
+ + +
+ + diff --git a/test/fixtures/templates/single-readonly-input.html b/test/fixtures/templates/single-readonly-input.html new file mode 100644 index 0000000..0088118 --- /dev/null +++ b/test/fixtures/templates/single-readonly-input.html @@ -0,0 +1,19 @@ + + + + + Title + + +
+ + +
+ + diff --git a/tsconfig.json b/tsconfig.json index 2c85b2d..105101c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,35 +1,20 @@ { - // see https://www.typescriptlang.org/tsconfig to better understand tsconfigs "include": ["src", "types"], "compilerOptions": { "module": "esnext", "lib": ["dom", "esnext"], "importHelpers": true, - // output .d.ts declaration files for consumers "declaration": true, - // output .js.map sourcemap files for consumers "sourceMap": true, - // match output dir to input dir. e.g. dist/index instead of dist/src/index - "rootDir": "./src", - // stricter type-checking for stronger correctness. Recommended by TS "strict": true, - // linter checks for common issues "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, - // noUnused* overlap with @typescript-eslint/no-unused-vars, can disable if duplicative "noUnusedLocals": true, "noUnusedParameters": true, - // use Node's module resolution algorithm, instead of the legacy TS one "moduleResolution": "node", - // transpile JSX to React.createElement - "jsx": "react", - // interop between ESM and CJS modules. Recommended by TS "esModuleInterop": true, - // significant perf increase by skipping checking .d.ts files, particularly those in node_modules. Recommended by TS "skipLibCheck": true, - // error out if import and file system have a casing mismatch. Recommended by TS "forceConsistentCasingInFileNames": true, - // `tsdx build` ignores this option, but it is commonly used when type-checking separately with `tsc` - "noEmit": true, + "noEmit": true } } diff --git a/yarn.lock b/yarn.lock index ada1485..18524f8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1305,6 +1305,15 @@ jest-diff "^25.2.1" pretty-format "^25.2.1" +"@types/jsdom@^16.2.10": + version "16.2.10" + resolved "https://registry.yarnpkg.com/@types/jsdom/-/jsdom-16.2.10.tgz#c05ea94682d035943ae2453b79d56178496b6653" + integrity sha512-q3aIjp3ehhVSXSbvNyuireAfvU2umRiZ2aLumyeZewCnoNaokrRDdTu5IvaeE9pzNtWHXrUnM9lb22Vl3W08EA== + dependencies: + "@types/node" "*" + "@types/parse5" "*" + "@types/tough-cookie" "*" + "@types/json-schema@^7.0.3", "@types/json-schema@^7.0.6": version "7.0.7" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad" @@ -1330,6 +1339,11 @@ resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== +"@types/parse5@*": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-6.0.0.tgz#38590dc2c3cf5717154064e3ee9b6947ee21b299" + integrity sha512-oPwPSj4a1wu9rsXTEGIJz91ISU725t0BmSnUhb57sI+M8XEmvUop84lzuiYdq0Y5M6xLY8DBPg0C2xEQKLyvBA== + "@types/prettier@^1.19.0": version "1.19.1" resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-1.19.1.tgz#33509849f8e679e4add158959fdb086440e9553f" @@ -1352,6 +1366,11 @@ resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e" integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw== +"@types/tough-cookie@*": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.0.tgz#fef1904e4668b6e5ecee60c52cc6a078ffa6697d" + integrity sha512-I99sngh224D0M7XgW1s120zxCt3VYQ3IQsuw3P3jbq5GG4yc79+ZjyKznyOGIQrflfylLgcfekeZW/vk0yng6A== + "@types/yargs-parser@*": version "20.2.0" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-20.2.0.tgz#dd3e6699ba3237f0348cd085e4698780204842f9" @@ -1562,7 +1581,7 @@ resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== -abab@^2.0.0: +abab@^2.0.0, abab@^2.0.3, abab@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.5.tgz#c0b678fb32d60fc1219c784d6a826fe385aeb79a" integrity sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q== @@ -1575,6 +1594,14 @@ acorn-globals@^4.3.2: acorn "^6.0.1" acorn-walk "^6.0.1" +acorn-globals@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" + integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== + dependencies: + acorn "^7.1.1" + acorn-walk "^7.1.1" + acorn-jsx@^5.2.0: version "5.3.1" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.1.tgz#fc8661e11b7ac1539c47dbfea2e72b3af34d267b" @@ -1585,6 +1612,11 @@ acorn-walk@^6.0.1: resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.2.0.tgz#123cb8f3b84c2171f1f7fb252615b1c78a6b1a8c" integrity sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA== +acorn-walk@^7.1.1: + version "7.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" + integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== + acorn-walk@^8.0.0: version "8.1.0" resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.1.0.tgz#d3c6a9faf00987a5e2b9bdb506c2aa76cd707f83" @@ -1600,7 +1632,7 @@ acorn@^7.1.0, acorn@^7.1.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== -acorn@^8.0.4: +acorn@^8.0.4, acorn@^8.1.0: version "8.2.2" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.2.2.tgz#c4574e4fea298d6e6ed4b85ab844b06dd59f26d6" integrity sha512-VrMS8kxT0e7J1EX0p6rI/E0FbfOVcvBpbIqHThFv+f8YrZIlMfVotYcXKVPmTvPW8sW5miJzfUFrrvthUZg8VQ== @@ -2913,7 +2945,7 @@ csso@^4.0.2: dependencies: css-tree "^1.1.2" -cssom@^0.4.1: +cssom@^0.4.1, cssom@^0.4.4: version "0.4.4" resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== @@ -2923,7 +2955,7 @@ cssom@~0.3.6: resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== -cssstyle@^2.0.0: +cssstyle@^2.0.0, cssstyle@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== @@ -2956,6 +2988,15 @@ data-urls@^1.1.0: whatwg-mimetype "^2.2.0" whatwg-url "^7.0.0" +data-urls@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" + integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== + dependencies: + abab "^2.0.3" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.0.0" + debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -2975,6 +3016,11 @@ decamelize@^1.2.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= +decimal.js@^10.2.1: + version "10.2.1" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.2.1.tgz#238ae7b0f0c793d3e3cea410108b35a2c01426a3" + integrity sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw== + decode-uri-component@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" @@ -3117,6 +3163,13 @@ domexception@^1.0.1: dependencies: webidl-conversions "^4.0.2" +domexception@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" + integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== + dependencies: + webidl-conversions "^5.0.0" + domutils@^1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" @@ -3298,6 +3351,18 @@ escodegen@^1.11.1: optionalDependencies: source-map "~0.6.1" +escodegen@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd" + integrity sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw== + dependencies: + esprima "^4.0.1" + estraverse "^5.2.0" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.6.1" + eslint-config-prettier@^6.0.0: version "6.15.0" resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-6.15.0.tgz#7f93f6cb7d45a92f1537a70ecc06366e1ac6fed9" @@ -4182,6 +4247,13 @@ html-encoding-sniffer@^1.0.2: dependencies: whatwg-encoding "^1.0.1" +html-encoding-sniffer@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" + integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ== + dependencies: + whatwg-encoding "^1.0.5" + html-escaper@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" @@ -4576,6 +4648,11 @@ is-plain-object@^2.0.3, is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" +is-potential-custom-element-name@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" + integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== + is-reference@^1.1.2: version "1.2.1" resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.2.1.tgz#8b2dac0b371f4bc994fdeaba9eb542d03002d0b7" @@ -5153,6 +5230,38 @@ jsdom@^15.2.1: ws "^7.0.0" xml-name-validator "^3.0.0" +jsdom@^16.5.3: + version "16.5.3" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.5.3.tgz#13a755b3950eb938b4482c407238ddf16f0d2136" + integrity sha512-Qj1H+PEvUsOtdPJ056ewXM4UJPCi4hhLA8wpiz9F2YvsRBhuFsXxtrIFAgGBDynQA9isAMGE91PfUYbdMPXuTA== + dependencies: + abab "^2.0.5" + acorn "^8.1.0" + acorn-globals "^6.0.0" + cssom "^0.4.4" + cssstyle "^2.3.0" + data-urls "^2.0.0" + decimal.js "^10.2.1" + domexception "^2.0.1" + escodegen "^2.0.0" + html-encoding-sniffer "^2.0.1" + is-potential-custom-element-name "^1.0.0" + nwsapi "^2.2.0" + parse5 "6.0.1" + request "^2.88.2" + request-promise-native "^1.0.9" + saxes "^5.0.1" + symbol-tree "^3.2.4" + tough-cookie "^4.0.0" + w3c-hr-time "^1.0.2" + w3c-xmlserializer "^2.0.0" + webidl-conversions "^6.1.0" + whatwg-encoding "^1.0.5" + whatwg-mimetype "^2.3.0" + whatwg-url "^8.5.0" + ws "^7.4.4" + xml-name-validator "^3.0.0" + jsesc@^2.5.1: version "2.5.2" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" @@ -5394,7 +5503,7 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.5: +lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.5, lodash@^4.7.0: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -6158,6 +6267,11 @@ parse5@5.1.0: resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.0.tgz#c59341c9723f414c452975564c7c00a68d58acd2" integrity sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ== +parse5@6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" + integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== + pascal-case@^3.1.1: version "3.1.2" resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb" @@ -6697,7 +6811,7 @@ prr@~1.0.1: resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= -psl@^1.1.28: +psl@^1.1.28, psl@^1.1.33: version "1.8.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== @@ -6981,7 +7095,7 @@ request-promise-core@1.1.4: dependencies: lodash "^4.17.19" -request-promise-native@^1.0.7: +request-promise-native@^1.0.7, request-promise-native@^1.0.9: version "1.0.9" resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.9.tgz#e407120526a5efdc9a39b28a5679bf47b9d9dc28" integrity sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g== @@ -6990,7 +7104,7 @@ request-promise-native@^1.0.7: stealthy-require "^1.1.1" tough-cookie "^2.3.3" -request@^2.88.0: +request@^2.88.0, request@^2.88.2: version "2.88.2" resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== @@ -7279,6 +7393,13 @@ saxes@^3.1.9: dependencies: xmlchars "^2.1.1" +saxes@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" + integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== + dependencies: + xmlchars "^2.2.0" + schema-utils@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" @@ -7847,7 +7968,7 @@ svgo@^1.0.0: unquote "~1.1.1" util.promisify "~1.0.0" -symbol-tree@^3.2.2: +symbol-tree@^3.2.2, symbol-tree@^3.2.4: version "3.2.4" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== @@ -8027,6 +8148,15 @@ tough-cookie@^3.0.1: psl "^1.1.28" punycode "^2.1.1" +tough-cookie@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4" + integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg== + dependencies: + psl "^1.1.33" + punycode "^2.1.1" + universalify "^0.1.2" + tr46@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" @@ -8034,6 +8164,13 @@ tr46@^1.0.1: dependencies: punycode "^2.1.0" +tr46@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.0.2.tgz#03273586def1595ae08fedb38d7733cee91d2479" + integrity sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg== + dependencies: + punycode "^2.1.1" + ts-jest@^25.3.1: version "25.5.1" resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-25.5.1.tgz#2913afd08f28385d54f2f4e828be4d261f4337c7" @@ -8282,7 +8419,7 @@ unique-slug@^2.0.0: dependencies: imurmurhash "^0.1.4" -universalify@^0.1.0: +universalify@^0.1.0, universalify@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== @@ -8410,7 +8547,7 @@ vm-browserify@^1.0.1: resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== -w3c-hr-time@^1.0.1: +w3c-hr-time@^1.0.1, w3c-hr-time@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== @@ -8426,6 +8563,13 @@ w3c-xmlserializer@^1.1.2: webidl-conversions "^4.0.2" xml-name-validator "^3.0.0" +w3c-xmlserializer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" + integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== + dependencies: + xml-name-validator "^3.0.0" + walker@^1.0.7, walker@~1.0.5: version "1.0.7" resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" @@ -8463,6 +8607,16 @@ webidl-conversions@^4.0.2: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== +webidl-conversions@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" + integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== + +webidl-conversions@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" + integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== + webpack-bundle-analyzer@^4.4.0: version "4.4.1" resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.4.1.tgz#c71fb2eaffc10a4754d7303b224adb2342069da1" @@ -8536,6 +8690,15 @@ whatwg-url@^7.0.0: tr46 "^1.0.1" webidl-conversions "^4.0.2" +whatwg-url@^8.0.0, whatwg-url@^8.5.0: + version "8.5.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.5.0.tgz#7752b8464fc0903fec89aa9846fc9efe07351fd3" + integrity sha512-fy+R77xWv0AiqfLl4nuGUlQ3/6b5uNfQ4WAbGQVMYshCTCCPK9psC1nWh3XHuxGVCtlcDDQPQW1csmmIQo+fwg== + dependencies: + lodash "^4.7.0" + tr46 "^2.0.2" + webidl-conversions "^6.1.0" + which-boxed-primitive@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" @@ -8617,7 +8780,7 @@ write@1.0.3: dependencies: mkdirp "^0.5.1" -ws@^7.0.0, ws@^7.3.1: +ws@^7.0.0, ws@^7.3.1, ws@^7.4.4: version "7.4.5" resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.5.tgz#a484dd851e9beb6fdb420027e3885e8ce48986c1" integrity sha512-xzyu3hFvomRfXKH8vOFMU3OguG6oOvhXMo3xsGy3xWExqaM2dxBbVxuD99O7m3ZUFMvvscsZDqxfgMaRr/Nr1g== @@ -8627,7 +8790,7 @@ xml-name-validator@^3.0.0: resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== -xmlchars@^2.1.1: +xmlchars@^2.1.1, xmlchars@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==