From 168311e19969359e558efc2a999c71f753e77511 Mon Sep 17 00:00:00 2001 From: Brendan Bond Date: Thu, 16 May 2024 16:45:43 -0400 Subject: [PATCH] Devex/jsdoc migration (#5601) * wip: add linting jsdoc etc * replace esdoc with jsdoc * remove esdoc config file * lint a bunch of files and add lint yarn script * Adding esdocs to src/Element.js * jsdoc for Providers.js * update webform jsdoc types * minor * fix linting errors * update types for nested component * breadCrumbSettings -> breadcrumbSettings at line 142 * update formio.form.js jsdoc * Adding some jsdocs to src/components/_classes/component/Component.js * jsdoc for address provider base class and azure address * one warning left at line 16, did not want to alter constructor logic to fix * address provider jsdoc * Adding component class docs. * Working on utils eslint. * WIP: update jsdoc * update types to parent Form class; add builder options type * minor update * Re-export methods from @formio/core for the utils functions. * Re-adding findComponents. * JSDoc: Field.js * update formbuilder options; type listcomponent and child classes * type definitions for file providers * resolve FormBuilder eslint warnings * fix password strength linting warnings and fileProcessor lints * whoopsie - minor typo * Updated utils docs. * cleaned up lint errors * jsDoc added to Multvalue.js * JSDoc-Update: NestedComponent.js * fix linter warnings for Input, ListComponent, and Multivalue * lint fixes for Form, CalendarWidget, ListComponent.form.js * jsdoc updates for Well.form and ListComponent.form * updates to edit forms for list, time, unknown, url, and well * Adding types to utils. * jsdoc updates to textfield and textfield.form * Fixing typedocs on edit forms. * use generic edit form function definition * jsdoc updates to Tabs and TextArea * jsdoc updates to SelectBoxes, Select, Number, Hidden * Adding lint for Form. * jsdoc updates to day and editgrid * jsdoc updates to DataGrid * Fixing lint for pdf, wizard, and webform builder. * address through currency * Adding docs to edit forms in _classes. * Updated componments. * jsdoc updates to nested form * delete accidental addition * update package json script and lockfile --------- Co-authored-by: Travis Tidwell Co-authored-by: John Teague Co-authored-by: ryanformio Co-authored-by: Edwin Anciani Co-authored-by: Dezshaun Meeks --- .esdoc.json | 8 - .eslintignore | 10 + .eslintrc.js | 17 + .eslintrc.json | 38 - gulpfile.js | 9 - package.json | 11 +- src/Element.js | 141 +- src/Form.js | 209 +- src/FormBuilder.js | 43 +- src/PDF.js | 14 +- src/Webform.js | 3087 ++++++++--------- src/WebformBuilder.js | 21 +- src/Wizard.js | 56 +- .../PasswordStrength/PasswordStrengthAddon.js | 9 +- src/components/Components.js | 6 +- .../_classes/component/Component.form.js | 5 + .../_classes/component/Component.js | 595 +++- .../editForm/Component.edit.display.js | 8 - src/components/_classes/field/Field.js | 14 +- src/components/_classes/input/Input.js | 4 +- .../_classes/list/ListComponent.form.js | 5 + .../_classes/multivalue/Multivalue.js | 41 +- .../_classes/nested/NestedComponent.form.js | 5 + .../_classes/nested/NestedComponent.js | 200 +- .../nesteddata/NestedDataComponent.js | 3 +- src/components/address/Address.form.js | 5 + src/components/button/Button.form.js | 5 + src/components/button/Button.js | 5 + src/components/checkbox/Checkbox.form.js | 5 + src/components/columns/Columns.form.js | 5 + src/components/columns/Columns.js | 2 +- src/components/container/Container.form.js | 5 + src/components/content/Content.form.js | 5 + src/components/currency/Currency.form.js | 5 + src/components/currency/Currency.js | 3 +- src/components/datagrid/DataGrid.form.js | 5 + src/components/datagrid/DataGrid.js | 10 +- src/components/datamap/DataMap.form.js | 5 + src/components/datetime/DateTime.form.js | 5 + src/components/day/Day.form.js | 5 + src/components/day/Day.js | 35 +- src/components/editgrid/EditGrid.form.js | 5 + src/components/editgrid/EditGrid.js | 6 +- src/components/email/Email.form.js | 5 + src/components/fieldset/Fieldset.form.js | 5 + src/components/file/File.form.js | 5 + src/components/form/Form.form.js | 5 + src/components/form/Form.js | 23 +- src/components/hidden/Hidden.form.js | 5 + src/components/hidden/Hidden.js | 3 +- src/components/html/HTML.form.js | 5 + src/components/number/Number.form.js | 5 + src/components/number/Number.js | 3 +- src/components/panel/Panel.form.js | 5 + src/components/panel/Panel.js | 1 - src/components/password/Password.form.js | 5 + .../phonenumber/PhoneNumber.form.js | 5 + src/components/radio/Radio.form.js | 5 + src/components/radio/Radio.js | 7 +- src/components/recaptcha/ReCaptcha.form.js | 4 + src/components/select/Select.form.js | 5 + src/components/select/Select.js | 29 +- .../selectboxes/SelectBoxes.form.js | 5 + src/components/selectboxes/SelectBoxes.js | 16 +- src/components/signature/Signature.form.js | 5 + src/components/survey/Survey.form.js | 5 + src/components/table/Table.form.js | 5 + src/components/tabs/Tabs.form.js | 5 + src/components/tabs/Tabs.js | 3 +- src/components/tags/Tags.form.js | 5 + src/components/textarea/TextArea.form.js | 5 + src/components/textarea/TextArea.js | 4 +- src/components/textfield/TextField.form.js | 5 + src/components/textfield/TextField.js | 29 +- src/components/time/Time.form.js | 5 + src/components/unknown/Unknown.form.js | 5 + src/components/url/Url.form.js | 5 + src/components/well/Well.form.js | 5 + src/formio.form.js | 10 +- src/providers/Providers.js | 33 +- src/providers/address/AddressProvider.js | 100 +- src/providers/address/AzureAddressProvider.js | 43 +- .../address/CustomAddressProvider.js | 34 + .../address/GoogleAddressProvider.js | 101 +- .../address/NominatimAddressProvider.js | 39 +- src/providers/processor/fileProcessor.js | 6 + src/providers/storage/azure.js | 11 + src/providers/storage/base64.js | 4 + src/providers/storage/dropbox.js | 6 +- src/providers/storage/googleDrive.js | 7 + src/providers/storage/index.js | 2 + src/providers/storage/indexeddb.js | 4 + src/providers/storage/s3.js | 5 + src/providers/storage/url.js | 10 + src/providers/storage/util.js | 20 + src/utils/builder.js | 15 +- src/utils/calendarUtils.js | 27 +- src/utils/formUtils.js | 694 +--- src/utils/utils.js | 483 ++- src/widgets/CalendarWidget.js | 20 +- yarn.lock | 1230 +------ 101 files changed, 3769 insertions(+), 4057 deletions(-) delete mode 100644 .esdoc.json create mode 100644 .eslintignore create mode 100644 .eslintrc.js delete mode 100644 .eslintrc.json diff --git a/.esdoc.json b/.esdoc.json deleted file mode 100644 index 214fcb0f34..0000000000 --- a/.esdoc.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "source": "./src", - "destination": "./docs", - "plugins": [ - {"name": "esdoc-standard-plugin"}, - {"name": "esdoc-ecmascript-proposal-plugin", "option": {"all": true}} - ] - } diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000000..6575178e0a --- /dev/null +++ b/.eslintignore @@ -0,0 +1,10 @@ +node_modules +lib +dist +app +test +types +*.spec.js +*.unit.js +_site +docs diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000000..52e6c54d63 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,17 @@ +module.exports = { + "env": { + "browser": true, + "es2021": true, + "node": true + }, + "extends": ["eslint:recommended", "plugin:jsdoc/recommended-typescript-flavor"], + "parserOptions": { + "ecmaVersion": "latest", + "sourceType": "module" + }, + "plugins": ["jsdoc"], + "rules": { + "no-prototype-builtins": "off", + "no-unused-vars": ["error", { "argsIgnorePattern": "^_" }], + } +} diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 7417481951..0000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "parser": "@typescript-eslint/parser", - "extends": "formio", - "parserOptions": { - "ecmaVersion": 2020, - "sourceType": "module" - }, - "plugins": ["@typescript-eslint"], - "env": { - "browser": true, - "es2020": true, - "node": true, - "mocha": true - }, - "ignorePatterns": [ - "!.*rc.js" - ], - "rules": { - "max-len": [ - "off", - { - "code": 160, - "ignoreComments": true, - "ignoreStrings": true - } - ], - "max-statements": [2, 40], - "max-depth": [2, 10], - "no-console": "off", - "no-prototype-builtins": "off", - "prefer-const": "error", - "prefer-template": "error", - "object-curly-spacing": [ - "error", - "always" - ] - } -} diff --git a/gulpfile.js b/gulpfile.js index d0bd609d64..aad43eaec5 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -6,7 +6,6 @@ const concat = require('gulp-concat'); const replace = require('gulp-replace'); const rename = require('gulp-rename'); const cleanCSS = require('gulp-clean-css'); -const eslint = require('gulp-eslint'); const clean = require('gulp-clean'); // Clean lib folder. @@ -18,14 +17,6 @@ gulp.task('clean:lib', () => { }); gulp.task('clean', gulp.parallel('clean:dist', 'clean:lib')); -// ESLint -gulp.task('eslint', function eslintTask() { - return gulp.src(['./src/**/*.js', '!./src/**/*.spec.js']) - .pipe(eslint()) - .pipe(eslint.format()) - .pipe(eslint.failAfterError()); -}); - // Move font-awesome fonts into dist folder. gulp.task('builder-fonts', function builderFonts() { return gulp.src('./node_modules/bootstrap-icons/font/fonts/*').pipe(gulp.dest('dist/fonts')); diff --git a/package.json b/package.json index 31c0f1fa06..c4c803c818 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,7 @@ ], "scripts": { "build": "yarn doc && yarn lib && yarn dist", - "doc": "esdoc", + "doc": "typedoc", "dist": "gulp clean:dist && webpack --config webpack.config.js && webpack --config webpack.prod.js && gulp build", "lib": "gulp clean:lib && tsc --project tsconfig.cjs.json && tsc --project tsconfig.mjs.json && yarn lib:package", "lib:package": "node ./libpackage.js", @@ -50,7 +50,7 @@ "release": "yarn build-app && yarn deploy-s3", "tag": "VERSION=$(yarn version);git add -A; git commit -m \"Build $Version\";git push origin master;git tag v$VERSION;git push origin --tags;", "dopublish": "npm run build && npm run tag && npm publish", - "lint": "gulp eslint", + "lint": "eslint ./src --fix", "serve": "jekyll serve --config _config.yml,_config.dev.yml", "test": "mocha 'src/**/*.unit.js'", "test:updateRenders": "npm run lib && TZ=UTC node --require jsdom-global/register test/updateRenders.js", @@ -124,11 +124,8 @@ "chance": "^1.1.9", "ejs-loader": "^0.5.0", "escape-string-regexp": "^5.0.0", - "esdoc": "^1.1.0", - "esdoc-ecmascript-proposal-plugin": "^1.0.0", - "esdoc-standard-plugin": "^1.0.0", "eslint": "^8.57.0", - "eslint-config-formio": "^1.1.4", + "eslint-plugin-jsdoc": "^48.2.3", "fetch-mock": "^9.11.0", "file-loader": "^6.2.0", "flatpickr": "^4.6.13", @@ -137,7 +134,6 @@ "gulp-clean": "^0.4.0", "gulp-clean-css": "^4.3.0", "gulp-concat": "^2.6.1", - "gulp-eslint": "^6.0.0", "gulp-filter": "^7.0.0", "gulp-rename": "^2.0.0", "gulp-replace": "^1.1.3", @@ -168,6 +164,7 @@ "ts-loader": "^9.4.4", "ts-node": "^10.9.1", "tsc": "^2.0.4", + "typedoc": "^0.25.13", "typescript": "5.3.2", "webpack": "^5.90.3", "webpack-bundle-analyzer": "^4.10.2", diff --git a/src/Element.js b/src/Element.js index 91385e9bac..e40f112cb6 100644 --- a/src/Element.js +++ b/src/Element.js @@ -45,7 +45,6 @@ export default class Element { /** * An instance of the EventEmitter class to handle the emitting and registration of events. - * * @type {EventEmitter} */ this.events = (options && options.events) ? options.events : new EventEmitter(); @@ -53,7 +52,6 @@ export default class Element { this.defaultMask = null; /** * Conditional to show or hide helplinks in editForm - * * @type {*|boolean} */ this.helplinks = (this.options.helplinks === 'false') ? false : (this.options.helplinks || 'https://help.form.io'); @@ -61,7 +59,6 @@ export default class Element { /** * Register for a new event within this component. - * * @example * let component = new BaseComponent({ * type: 'textfield', @@ -71,12 +68,11 @@ export default class Element { * component.on('componentChange', (changed) => { * console.log('this element is changed.'); * }); - * - * * @param {string} event - The event you wish to register the handler for. - * @param {function} cb - The callback handler to handle this event. + * @param {Function} cb - The callback handler to handle this event. * @param {boolean} [internal] - This is an internal event handler. * @param {boolean} [once] - This event should only fire once. + * @returns {EventEmitter | void} - The event emitter instance. */ on(event, cb, internal, once = false) { if (!this.events) { @@ -95,9 +91,10 @@ export default class Element { /** * Register for a new single-fire event within this component. - * * @param {string} event - The event you wish to register the handler for. - * @param {function} cb - The callback handler to handle this event. + * @param {Function} cb - The callback handler to handle this event. + * @param {boolean} internal - This is an internal event handler. + * @returns {EventEmitter} - The event emitter instance. */ once(event, cb, internal) { return this.on(event, cb, internal, true); @@ -105,9 +102,8 @@ export default class Element { /** * Allow catching any event. - * - * @param cb - * @returns {this} + * @param {Function} cb - The callback handler to handle this event. + * @returns {EventEmitter | void} - The event emitter instance. */ onAny(cb) { if (!this.events) { @@ -119,9 +115,8 @@ export default class Element { /** * Removes the listener that will be fired when any event is emitted. - * - * @param cb - * @returns {this} + * @param {Function} cb - The callback handler to handle this event. + * @returns {EventEmitter | void} - The event emitter instance. */ offAny(cb) { if (!this.events) { @@ -133,9 +128,8 @@ export default class Element { /** * Removes a listener for a certain event. Not passing the 2nd arg will remove all listeners for that event. - * * @param {string} event - The event you wish to register the handler for. - * @param {function|undefined} cb - The callback handler to handle this event. + * @param {Function | undefined} cb - The callback handler to handle this event. */ off(event, cb) { if (!this.events) { @@ -161,9 +155,8 @@ export default class Element { /** * Emit a new event. - * * @param {string} event - The event to emit. - * @param {Object} data - The data to emit with the handler. + * @param {object} data - The data to emit with the handler. */ emit(event, ...data) { if (this.events) { @@ -173,9 +166,8 @@ export default class Element { /** * Check if the component has an event handler set up for the event. - * * @param {string} event - The event name. - * @returns {boolean} + * @returns {boolean} - TRUE if the event is registered, FALSE otherwise. */ hasEventHandler(event) { if (!this.events) { @@ -195,15 +187,12 @@ export default class Element { /** * Wrapper method to add an event listener to an HTML element. - * - * @param obj - * The DOM element to add the event to. - * @param type - * The event name to add. - * @param func - * The callback function to be executed when the listener is triggered. - * @param persistent - * If this listener should persist beyond "destroy" commands. + * @param {HtmlElement} obj - The DOM element to add the event to. + * @param {string} type - The event name to add. + * @param {Function} func - The callback function to be executed when the listener is triggered. + * @param {boolean} persistent - If this listener should persist beyond "destroy" commands. + * @param {boolean} capture - If this listener should be executed in the capture phase. + * @returns {void | this} - The instance of the element. */ addEventListener(obj, type, func, persistent, capture) { if (!obj) { @@ -224,9 +213,10 @@ export default class Element { /** * Remove an event listener from the object. - * - * @param obj - * @param type + * @param {HTMLElement} obj - The DOM element to remove the event from. + * @param {string} type - The event name to remove. + * @param {Function} func - The callback function to remove. + * @returns {this | void} - The instance of the element. */ removeEventListener(obj, type, func = null) { const indexes = []; @@ -280,6 +270,7 @@ export default class Element { /** * Removes all event listeners attached to this component. + * @param {boolean} all - If all events should be removed, including external events. */ destroy(all = false) { this.removeEventListeners(); @@ -291,9 +282,9 @@ export default class Element { /** * Append an HTML DOM element to a container. - * - * @param element - * @param container + * @param {HTMLElement} element - The DOM element to append. + * @param {HTMLElement} container - The DOM element that is the container of the element getting appended. + * @returns {this} - The instance of the element. */ appendTo(element, container) { container?.appendChild(element); @@ -302,9 +293,9 @@ export default class Element { /** * Prepend an HTML DOM element to a container. - * * @param {HTMLElement} element - The DOM element to prepend. * @param {HTMLElement} container - The DOM element that is the container of the element getting prepended. + * @returns {this} - The instance of the element. */ prependTo(element, container) { if (container) { @@ -327,9 +318,9 @@ export default class Element { /** * Removes an HTML DOM element from its bounding container. - * * @param {HTMLElement} element - The element to remove. * @param {HTMLElement} container - The DOM element that is the container of the element to remove. + * @returns {this} - The instance of the element. */ removeChildFrom(element, container) { if (container && container.contains(element)) { @@ -346,12 +337,10 @@ export default class Element { /** * Alias for document.createElement. - * * @param {string} type - The type of element to create - * @param {Object} attr - The element attributes to add to the created element. + * @param {object} attr - The element attributes to add to the created element. * @param {Various} children - Child elements. Can be a DOM Element, string or array of both. - * - * @return {HTMLElement} - The created element. + * @returns {HTMLElement} - The created element. */ ce(type, attr, children = null) { // console.warn('Call to deprecated this.ce(). Dom elements should be created with templates, not manually with ce.'); @@ -370,8 +359,9 @@ export default class Element { /** * Append different types of children. - * - * @param child + * @param {HTMLElement} element - The element to append to. + * @param {HTMLElement} child - The child element to append. + * @returns {this} - The instance of the element. */ appendChild(element, child) { if (Array.isArray(child)) { @@ -396,16 +386,19 @@ export default class Element { return mask.map((char) => (char instanceof RegExp) ? this.placeholderChar : char).join(''); } + /** + * Get the placeholder character for the input mask. + * @returns {string} - The placeholder character. + */ get placeholderChar() { return this.component?.inputMaskPlaceholderChar || '_'; } /** * Sets the input mask for an input. - * * @param {HTMLElement} input - The html input to apply the mask to. - * @param {String} inputMask - The input mask to add to this input. - * @param {Boolean} usePlaceholder - Set the mask placeholder on the input. + * @param {string} inputMask - The input mask to add to this input. + * @param {boolean} usePlaceholder - Set the mask placeholder on the input. */ setInputMask(input, inputMask, usePlaceholder) { if (input && inputMask) { @@ -441,9 +434,9 @@ export default class Element { /** * Translate a text using the i18n system. - * * @param {string|Array} text - The i18n identifier. - * @param {Object} params - The i18n parameters to use for translation. + * @param {...any} args - The arguments to pass to the i18n translation. + * @returns {string} - The translated text. */ t(text, ...args) { return this.i18next ? this.i18next.t(text, ...args): text; @@ -451,8 +444,8 @@ export default class Element { /** * Alias to create a text node. - * @param text - * @returns {Text} + * @param {string} text - The text to create. + * @returns {HtmlElement} - The created text node. */ text(text) { return document.createTextNode(this.t(text)); @@ -461,7 +454,7 @@ export default class Element { /** * Adds an object of attributes onto an element. * @param {HtmlElement} element - The element to add the attributes to. - * @param {Object} attr - The attributes to add to the input element. + * @param {object} attr - The attributes to add to the input element. */ attr(element, attr) { if (!element) { @@ -485,6 +478,9 @@ export default class Element { * Determines if an element has a class. * * Taken from jQuery https://j11y.io/jquery/#v=1.5.0&fn=jQuery.fn.hasClass + * @param {HTMLElement} element - The element to check for the class. + * @param {string} className - The class to check for. + * @returns {boolean} - TRUE if the element has the class, FALSE otherwise. */ hasClass(element, className) { if (!element) { @@ -497,11 +493,9 @@ export default class Element { /** * Adds a class to a DOM element. - * - * @param element - * The element to add a class to. - * @param className - * The name of the class to add. + * @param {HTMLElement} element - The element to add a class to. + * @param {string} className - The name of the class to add. + * @returns {this} - The instance of the element. */ addClass(element, className) { if (!element || !(element instanceof HTMLElement)) { @@ -518,11 +512,9 @@ export default class Element { /** * Remove a class from a DOM element. - * - * @param element - * The DOM element to remove the class from. - * @param className - * The name of the class that is to be removed. + * @param {HTMLElement} element - The DOM element to remove the class from. + * @param {string} className - The name of the class that is to be removed. + * @returns {this} - The instance of the element. */ removeClass(element, className) { if (!element || !className || !(element instanceof HTMLElement)) { @@ -540,7 +532,6 @@ export default class Element { /** * Empty's an HTML DOM element. - * * @param {HTMLElement} element - The element you wish to empty. */ empty(element) { @@ -553,9 +544,8 @@ export default class Element { /** * Create an evaluation context for all script executions and interpolations. - * - * @param additional - * @return {*} + * @param {object} additional - Additional context to apply to the evaluation context. + * @returns {*} - The evaluation context. */ evalContext(additional) { return Object.assign({ @@ -580,10 +570,10 @@ export default class Element { /** * Performs an interpolation using the evaluation context of this component. - * - * @param string - * @param data - * @return {XML|string|*|void} + * @param {string} string - The string to interpolate. + * @param {object} data - The data to use in the interpolation. + * @param {object} options - The options to pass to the interpolation. + * @returns {XML|string|*|void} - The interpolated string. */ interpolate(string, data, options = {}) { if (typeof string !== 'function' && (this.component.content || this.component.html) @@ -601,12 +591,11 @@ export default class Element { /** * Performs an evaluation using the evaluation context of this component. - * - * @param func - * @param args - * @param ret - * @param tokenize - * @return {*} + * @param {string|Function|object} func - The function or string to evaluate. + * @param {object} args - The arguments to pass to the evaluation. + * @param {string} ret - The name of the variable within the evaluation context to return. + * @param {boolean} tokenize - Determines if it should replace all {{ }} token references with actual data. + * @returns {*} - The result of the evaluation. */ evaluate(func, args, ret, tokenize) { return FormioUtils.evaluate(func, this.evalContext(args), ret, tokenize); @@ -614,7 +603,7 @@ export default class Element { /** * Allow for options to hook into the functionality of this renderer. - * @return {*} + * @returns {*} - The result of the hook function. */ hook() { const name = arguments[0]; diff --git a/src/Form.js b/src/Form.js index adce853a8c..a016ab88d8 100644 --- a/src/Form.js +++ b/src/Form.js @@ -5,29 +5,129 @@ import templates from './templates'; import * as FormioUtils from './utils/utils'; export default class Form extends Element { + /** + * Represents a JSON value. + * @typedef {(string | number | boolean | null | JSONArray | JSONObject)} JSON + */ + +/** + * Represents a JSON array. + * @typedef {Array} JSONArray + */ + +/** + * Represents a JSON object. + * @typedef {{[key: string]: JSON}} JSONObject + */ + +/** + * @typedef {object} FormioHooks + * @property {Function} [beforeSubmit] - Called before a submission is made. + * @property {Function} [beforeCancel] - Called before a cancel is made. + * @property {Function} [beforeNext] - Called before the next page is navigated to. + * @property {Function} [beforePrev] - Called before the previous page is navigated to. + * @property {Function} [attachComponent] - Called when a component is attached. + * @property {Function} [setDataValue] - Called when a data value is set. + * @property {Function} [addComponents] - Called when components are added. + * @property {Function} [addComponent] - Called when a component is added. + * @property {Function} [customValidation] - Called when a custom validation is made. + * @property {Function} [attachWebform] - Called when a webform is attached. + */ + +/** + * @typedef {object} SanitizeConfig + * @property {string[]} [addAttr] - The html attributes to allow with sanitization. + * @property {string[]} [addTags] - The html tags to allow with sanitization. + * @property {string[]} [allowedAttrs] - The html attributes to allow with sanitization. + * @property {string[]} [allowedTags] - The html tags to allow with sanitization. + * @property {string[]} [allowedUriRegex] - The regex for allowed URIs. + * @property {string[]} [addUriSafeAttr] - The URI attributes to allow with sanitization. + */ + +/** + * @typedef {object} ButtonSettings + * @property {boolean} [showPrevious] - Show the previous button in wizard forms. + * @property {boolean} [showNext] - Show the next button in wizard forms. + * @property {boolean} [showCancel] - Show the cancel button in wizard forms. + * @property {boolean} [showSubmit] - Show the submit button in wizard forms. + */ + +/** + * @typedef {object} FormOptions + * @property {boolean} [saveDraft] - Enable the save draft feature. + * @property {number} [saveDraftThrottle] - The throttle for the save draft feature. + * @property {boolean} [readOnly] - Set this form to readOnly. + * @property {boolean} [noAlerts] - Disable the alerts dialog. + * @property {{[key: string]: string}} [i18n] - The translation file for this rendering. + * @property {string} [template] - Custom logic for creation of elements. + * @property {boolean} [noDefaults] - Exclude default values from the settings. + * @property {any} [fileService] - The file service for this form. + * @property {EventEmitter} [events] - The EventEmitter for this form. + * @property {string} [language] - The language to render this form in. + * @property {{[key: string]: string}} [i18next] - The i18next configuration for this form. + * @property {boolean} [viewAsHtml] - View the form as raw HTML. + * @property {'form' | 'html' | 'flat' | 'builder' | 'pdf'} [renderMode] - The render mode for this form. + * @property {boolean} [highlightErrors] - Highlight any errors on the form. + * @property {string} [componentErrorClass] - The error class for components. + * @property {any} [templates] - The templates for this form. + * @property {string} [iconset] - The iconset for this form. + * @property {import('@formio/core').Component[]} [components] - The components for this form. + * @property {{[key: string]: boolean}} [disabled] - Disabled components for this form. + * @property {boolean} [showHiddenFields] - Show hidden fields. + * @property {{[key: string]: boolean}} [hide] - Hidden components for this form. + * @property {{[key: string]: boolean}} [show] - Components to show for this form. + * @property {Formio} [formio] - The Formio instance for this form. + * @property {string} [decimalSeparator] - The decimal separator for this form. + * @property {string} [thousandsSeparator] - The thousands separator for this form. + * @property {FormioHooks} [hooks] - The hooks for this form. + * @property {boolean} [alwaysDirty] - Always be dirty. + * @property {boolean} [skipDraftRestore] - Skip restoring a draft. + * @property {'form' | 'wizard' | 'pdf'} [display] - The display for this form. + * @property {string} [cdnUrl] - The CDN url for this form. + * @property {boolean} [flatten] - Flatten the form. + * @property {boolean} [sanitize] - Sanitize the form. + * @property {SanitizeConfig} [sanitizeConfig] - The sanitize configuration for this form. + * @property {ButtonSettings} [buttonSettings] - The button settings for this form. + * @property {object} [breadcrumbSettings] - The breadcrumb settings for this form. + * @property {boolean} [allowPrevious] - Allow the previous button (for Wizard forms). + * @property {string[]} [wizardButtonOrder] - The order of the buttons (for Wizard forms). + * @property {boolean} [showCheckboxBackground] - Show the checkbox background. + * @property {number} [zoom] - The zoom for PDF forms. + */ + /** * Creates an easy to use interface for embedding webforms, pdfs, and wizards into your application. - * - * @param {Object} element - The DOM element you wish to render this form within. - * @param {Object | string} form - Either a Form JSON schema or the URL of a hosted form via. form.io. - * @param {Object} options - The options to create a new form instance. - * @param {boolean} options.readOnly - Set this form to readOnly - * @param {boolean} options.noAlerts - Set to true to disable the alerts dialog. - * @param {boolean} options.i18n - The translation file for this rendering. @see https://github.com/formio/formio.js/blob/master/i18n.js - * @param {boolean} options.template - Provides a way to inject custom logic into the creation of every element rendered within the form. - * + * @param {object} elementOrForm - The DOM element you wish to render this form within, or the form definition. + * @param {object | string | FormOptions} formOrOptions - A Form JSON schema, the URL of a hosted form, or the form options. + * @param {FormOptions} [options] - The options to create a new form instance. * @example * import Form from '@formio/js/Form'; * const form = new Form(document.getElementById('formio'), 'https://examples.form.io/example'); * form.build(); */ - constructor(...args) { - let options = args[0] instanceof HTMLElement ? args[2] : args[1]; + + /** + * @type {FormOptions} - the options for this Form. + */ + options; + + constructor(elementOrForm, formOrOptions, options = {}) { + let element, form, formOptions; + if (elementOrForm instanceof HTMLElement) { + element = elementOrForm; + form = formOrOptions; + formOptions = options; + } + else { + element = null; + form = elementOrForm; + formOptions = formOrOptions || {}; + } if (Formio.options && Formio.options.form) { - options = Object.assign(options, Formio.options.form); + formOptions = Object.assign(formOptions, Formio.options.form); } - super(options); + super(formOptions); if (this.options.useSessionToken) { Formio.useSessionToken(this.options); @@ -39,30 +139,22 @@ export default class Form extends Element { }); this.instance = null; - if (args[0] instanceof HTMLElement) { + if (element) { if (this.element) { delete this.element.component; } - this.element = args[0]; - this.options = args[2] || {}; - this.options.events = this.events; - this.setForm(args[1]) - .then(() => this.readyResolve(this.instance)) - .catch(this.readyReject); + this.element = element; } - else if (args[0]) { + else { this.element = null; - this.options = args[1] || {}; - this.options.events = this.events; - this.setForm(args[0]) + } + if (form) { + this.setForm(form) .then(() => this.readyResolve(this.instance)) .catch(this.readyReject); } - else { - this.element = null; - this.options = {}; - this.options.events = this.events; - } + this.options = formOptions; + this.options.events = this.events; this.display = ''; } @@ -113,9 +205,8 @@ export default class Form extends Element { /** * Create a new form instance provided the display of the form. - * * @param {string} display - The display of the form, either "wizard", "form", or "pdf" - * @return {*} + * @returns {Webform|Wizard|PDF} - The new form instance for the display. */ create(display) { if (this.options && (this.options.flatten || this.options.renderMode === 'flat')) { @@ -133,9 +224,8 @@ export default class Form extends Element { /** * Sets the form. Either as JSON or a URL to a form JSON schema. - * * @param {string|object} formParam - Either the form JSON or the URL of the form json. - * @return {*} + * @returns {void} */ set form(formParam) { this.setForm(formParam); @@ -164,12 +254,11 @@ export default class Form extends Element { } /** - * Check Subdirectories path and provide correct options - * - * @param {string} url - The the URL of the form json. - * @param {form} object - The form json. - * @return {object} The initial options with base and project. - */ + * Check Subdirectories path and provide correct options + * @param {string} url - The the URL of the form json. + * @param {import('@formio/core').Form} form - The form json. + * @returns {object} The initial options with base and project. + */ getFormInitOptions(url, form) { const options = {}; const index = url.indexOf(form?.path); @@ -195,6 +284,11 @@ export default class Form extends Element { return {}; } + /** + * Sets the form to the JSON schema of a form. + * @param {import('@formio/core').Form} formParam - The form JSON to set this form to. + * @returns {Promise} - The webform instance that was created. + */ setForm(formParam) { let result; formParam = formParam || this.form; @@ -258,8 +352,7 @@ export default class Form extends Element { /** * Returns the loaded forms JSON. - * - * @return {object} - The loaded form's JSON + * @returns {object} - The loaded form's JSON */ get form() { return this._form; @@ -267,9 +360,8 @@ export default class Form extends Element { /** * Changes the display of the form. - * * @param {string} display - The display to set this form. Either "wizard", "form", or "pdf" - * @return {Promise} + * @returns {Promise} - The form instance that was created after changing the display. */ setDisplay(display) { if ((this.display === display) && this.instance) { @@ -314,9 +406,9 @@ export default class Form extends Element { /** * Sanitize an html string. - * - * @param string - * @returns {*} + * @param {string} dirty - The dirty html string to sanitize. + * @param {boolean} forceSanitize - If the string should be force sanitized. + * @returns {string} - The sanitized html string. */ sanitize(dirty, forceSanitize) { // If Sanitize is turned off @@ -336,8 +428,7 @@ export default class Form extends Element { /** * Build a new form. - * - * @return {Promise} + * @returns {Promise} - The form instance that was created. */ build() { if (!this.instance) { @@ -400,16 +491,20 @@ export default class Form extends Element { Formio.embedForm = (embed) => Form.embed(embed); /** - * Factory that creates a new form based on the form parameters. - * - * @param element {HMTLElement} - The HTML Element to add this form to. - * @param form {string|Object} - The src of the form, or a form object. - * @param options {Object} - The options to create this form. - * - * @return {Promise} - When the form is instance is ready. + * Creates an easy to use interface for embedding webforms, pdfs, and wizards into your application. + * @param {object} elementOrForm - The DOM element you wish to render this form within, or the form definition. + * @param {object | string | FormOptions} formOrOptions - A Form JSON schema, the URL of a hosted form, or the form options. + * @param {FormOptions} [options] - The options to create a new form instance. + * @returns {Promise} - The form instance that was created. + * @example + * import { Formio } from '@formio/js'; + * Formio.createForm(document.getElementById('formio'), 'https://examples.form.io/example'); */ -Formio.createForm = (...args) => { - return (new Form(...args)).ready; +Formio.createForm = (elementOrForm, formOrOptions, options) => { + return (new Form(elementOrForm, formOrOptions, options)).ready; }; Formio.Form = Form; + + +export { }; diff --git a/src/FormBuilder.js b/src/FormBuilder.js index 56e7a2e404..8595037f21 100644 --- a/src/FormBuilder.js +++ b/src/FormBuilder.js @@ -3,7 +3,36 @@ import Builders from './builders'; import Form from './Form'; export default class FormBuilder extends Form { + /** + * @typedef FormBuilderOptions + * @property {string[]} [disabled] - An array of "keys" of components that should be disabled within the form builder. Example: ['firstName', 'lastName'] + * @property {boolean} [noNewEdit] - When set to TRUE no modal is shown when a component is dragged onto the form. + * @property {boolean} [noDefaultSubmitButton] - Set to TRUE to not include the default submit button in Webforms. + * @property {boolean} [alwaysConfirmComponentRemoval] - Set to TRUE to always require confirmation before removing a component. + * @property {object} [formConfig] - Form configurations to apply to forms being created. These configurations are added to the "config" property of the form object. + * @property {string} [resourceTag] - The tag to use to query for the "Existing Resource Fields" section of the builder. + * @property {import('./Form').FormOptions} [editForm] - The options to apply to the Edit Form (the form that shows inside the modal when you edit a component). + * @property {string} [language] - The language to load into the form builder. + * @property {object} [builder] - The builder options to pass to the builder. + * @property {'form'|'wizard'|'pdf'} [display] - The display mode of the builder. + * @property {string} [resourceFilter] - Filter applied to the resources that appear in the builder's Existing Resource Fields. + * @property {boolean} [noSource] - When set to TRUE, the resource ID in the builder's Existing Resource Fields will not be linked. + * @property {boolean} [showFullJsonSchema] - When set to TRUE, the full JSON schema will be displayed in the JSON edit menu. + */ + + /** @type {FormBuilderOptions} */ static options = {}; + + /** @type {FormBuilderOptions} */ + options; + + /** + * Creates a new form builder. + * @param {HTMLElement} element - The HTML element to place the form builder. + * @param {string | object} form - The form to pass to the builder + * @param {FormBuilderOptions} options - The options to create this builder. + * @returns {FormBuilder} - The form builder instance. + */ constructor(element, form, options) { form = form || {}; options = options || {}; @@ -27,15 +56,13 @@ export default class FormBuilder extends Form { /** * Factory that creates a new form builder based on the form parameter. - * - * @param element {HMTLElement} - The HTML Element to add this form to. - * @param form {string|Object} - The src of the form, or a form object. - * @param options {Object} - The options to create this form. - * - * @return {Promise} - When the form is instance is ready. + * @param {HTMLElement} element - The HTML Element to add this form to. + * @param {string|object} form - The src of the form, or a form object. + * @param {object} options - The options to create this form. + * @returns {Promise} - When the form is instance is ready. */ -Formio.builder = (...args) => { - return (new FormBuilder(...args)).ready; +Formio.builder = (element, form, options) => { + return (new FormBuilder(element, form, options)).ready; }; Formio.FormBuilder = FormBuilder; diff --git a/src/PDF.js b/src/PDF.js index 7f5192d441..c99fdaeb9a 100644 --- a/src/PDF.js +++ b/src/PDF.js @@ -162,8 +162,7 @@ export default class PDF extends Webform { /** * Get the submission from the iframe. - * - * @return {Promise} + * @returns {Promise} - The submission from the iframe. */ getSubmission() { return new Promise((resolve) => { @@ -174,9 +173,8 @@ export default class PDF extends Webform { /** * Ensure we have the submission from the iframe before we submit the form. - * - * @param options - * @return {*} + * @param {any} options - The options for submission. + * @returns {Promise} - Resolves when the form is submitted. */ submitForm(options = {}) { this.postMessage({ name: 'getErrors' }); @@ -228,9 +226,9 @@ export default class PDF extends Webform { /** * Set's the value of this form component. - * - * @param submission - * @param flags + * @param {import('@formio/core').Submission} submission - The submission JSON to set the value of this form. + * @param {any} flags - The flags to use when setting the submission. + * @returns {boolean} - If the value changed or not. */ setValue(submission, flags = {}) { const changed = super.setValue(submission, flags); diff --git a/src/Webform.js b/src/Webform.js index 2f306ce240..d89b8c9d1b 100644 --- a/src/Webform.js +++ b/src/Webform.js @@ -1,22 +1,21 @@ -import _ from 'lodash'; -import moment from 'moment'; -import { compareVersions } from 'compare-versions'; -import { Component } from '@formio/core'; -import EventEmitter from './EventEmitter'; -import i18nDefaults from './i18n'; -import { Formio } from './Formio'; -import Components from './components/Components'; -import NestedDataComponent from './components/_classes/nesteddata/NestedDataComponent'; +import _ from "lodash"; +import moment from "moment"; +import { compareVersions } from "compare-versions"; +import EventEmitter from "./EventEmitter"; +import i18nDefaults from "./i18n"; +import { Formio } from "./Formio"; +import Components from "./components/Components"; +import NestedDataComponent from "./components/_classes/nesteddata/NestedDataComponent"; import { - fastCloneDeep, - currentTimezone, - unescapeHTML, - getStringFromComponentPath, - searchComponents, - convertStringToHTMLElement, - getArrayFromComponentPath, -} from './utils/utils'; -import { eachComponent } from './utils/formUtils'; + fastCloneDeep, + currentTimezone, + unescapeHTML, + getStringFromComponentPath, + searchComponents, + convertStringToHTMLElement, + getArrayFromComponentPath, +} from "./utils/utils"; +import { eachComponent } from "./utils/formUtils"; // Initialize the available forms. Formio.forms = {}; @@ -24,1706 +23,1662 @@ Formio.forms = {}; // Allow people to register components. Formio.registerComponent = Components.setComponent; +/** + * + * @param {any} icons - The icons to use. + * @returns {any} - The icon set. + */ function getIconSet(icons) { - if (icons === 'fontawesome') { - return 'fa'; - } - return icons || ''; + if (icons === "fontawesome") { + return "fa"; + } + return icons || ""; } +/** + * + * @param {any} options - The options to get. + * @returns {any} - The options. + */ function getOptions(options) { - options = _.defaults(options, { - submitOnEnter: false, - iconset: getIconSet((options && options.icons) ? options.icons : Formio.icons), - i18next: null, - saveDraft: false, - alwaysDirty: false, - saveDraftThrottle: 5000, - display: 'form', - cdnUrl: Formio.cdn.baseUrl - }); - if (!options.events) { - options.events = new EventEmitter(); - } - return options; + options = _.defaults(options, { + submitOnEnter: false, + iconset: getIconSet(options && options.icons ? options.icons : Formio.icons), + i18next: null, + saveDraft: false, + alwaysDirty: false, + saveDraftThrottle: 5000, + display: "form", + cdnUrl: Formio.cdn.baseUrl, + }); + if (!options.events) { + options.events = new EventEmitter(); + } + return options; } /** - * Represents a JSON value. - * @typedef {(string | number | boolean | null | JSONArray | JSONObject)} JSON + * Renders a Form.io form within the webpage. */ +export default class Webform extends NestedDataComponent { + /** + * @type {import('Form').FormOptions} - the options for this Webform. + */ + options; -/** - * Represents a JSON array. - * @typedef {Array} JSONArray - */ + /** + * Creates a new Form instance. + * @param {HTMLElement | object | import('Form').FormOptions} [elementOrOptions] - The DOM element to render this form within or the options to create this form instance. + * @param {import('Form').FormOptions} [options] - The options to create a new form instance. + */ + constructor(elementOrOptions, options) { + let element, formOptions; + if (elementOrOptions instanceof HTMLElement || options) { + element = elementOrOptions; + formOptions = options; + } else { + formOptions = elementOrOptions; + } + super(null, getOptions(formOptions)); -/** - * Represents a JSON object. - * @typedef {{[key: string]: JSON}} JSONObject - */ + this.setElement(element); -/** - * @typedef {Object} FormioHooks - * @property {function} [beforeSubmit] - * @property {function} [beforeCancel] - * @property {function} [beforeNext] - * @property {function} [beforePrev] - * @property {function} [attachComponent] - * @property {function} [setDataValue] - * @property {function} [addComponents] - * @property {function} [addComponent] - * @property {function} [customValidation] - * @property {function} [attachWebform] - */ + // Keep track of all available forms globally. + Formio.forms[this.id] = this; -/** - * @typedef {Object} SanitizeConfig - * @property {string[]} [addAttr] - * @property {string[]} [addTags] - * @property {string[]} [allowedAttrs] - * @property {string[]} [allowedTags] - * @property {string[]} [allowedUriRegex] - * @property {string[]} [addUriSafeAttr] - */ + // Set the base url. + if (this.options.baseUrl) { + Formio.setBaseUrl(this.options.baseUrl); + } -/** - * @typedef {Object} ButtonSettings - * @property {boolean} [showPrevious] - * @property {boolean} [showNext] - * @property {boolean} [showCancel] - * @property {boolean} [showSubmit] - */ + /** + * The type of this element. + * @type {string} + */ + this.type = "form"; + this._src = ""; + this._loading = false; + this._form = {}; + this.draftEnabled = false; + this.savingDraft = true; + if (this.options.saveDraftThrottle) { + this.triggerSaveDraft = _.throttle( + this.saveDraft.bind(this), + this.options.saveDraftThrottle + ); + } else { + this.triggerSaveDraft = this.saveDraft.bind(this); + } -/** - * @typedef {Object} FormOptions - * @property {boolean} [saveDraft] - Enable the save draft feature. - * @property {number} [saveDraftThrottle] - The throttle for the save draft feature. - * @property {boolean} [readOnly] - Set this form to readOnly. - * @property {boolean} [noAlerts] - Disable the alerts dialog. - * @property {{[key: string]: string}} [i18n] - The translation file for this rendering. - * @property {string} [template] - Custom logic for creation of elements. - * @property {boolean} [noDefaults] - Exclude default values from the settings. - * @property {any} [fileService] - The file service for this form. - * @property {EventEmitter} [events] - The EventEmitter for this form. - * @property {string} [language] - The language to render this form in. - * @property {{[key: string]: string}} [i18next] - The i18next configuration for this form. - * @property {boolean} [viewAsHtml] - View the form as raw HTML. - * @property {'form' | 'html' | 'flat' | 'builder' | 'pdf'} [renderMode] - The render mode for this form. - * @property {boolean} [highlightErrors] - Highlight any errors on the form. - * @property {string} [componentErrorClass] - The error class for components. - * @property {any} [templates] - The templates for this form. - * @property {string} [iconset] - The iconset for this form. - * @property {Component[]} [components] - The components for this form. - * @property {{[key: string]: boolean}} [disabled] - Disabled components for this form. - * @property {boolean} [showHiddenFields] - Show hidden fields. - * @property {{[key: string]: boolean}} [hide] - Hidden components for this form. - * @property {{[key: string]: boolean}} [show] - Components to show for this form. - * @property {Formio} [formio] - The Formio instance for this form. - * @property {string} [decimalSeparator] - The decimal separator for this form. - * @property {string} [thousandsSeparator] - The thousands separator for this form. - * @property {FormioHooks} [hooks] - The hooks for this form. - * @property {boolean} [alwaysDirty] - Always be dirty. - * @property {boolean} [skipDraftRestore] - Skip restoring a draft. - * @property {'form' | 'wizard' | 'pdf'} [display] - The display for this form. - * @property {string} [cdnUrl] - The CDN url for this form. - * @property {boolean} [flatten] - Flatten the form. - * @property {boolean} [sanitize] - Sanitize the form. - * @property {SanitizeConfig} [sanitizeConfig] - The sanitize configuration for this form. - * @property {ButtonSettings} [buttonSettings] - The button settings for this form. - * @property {Object} [breadCrumbSettings] - The breadcrumb settings for this form. - * @property {boolean} [allowPrevious] - Allow the previous button (for Wizard forms). - * @property {string[]} [wizardButtonOrder] - The order of the buttons (for Wizard forms). - * @property {boolean} [showCheckboxBackground] - Show the checkbox background. - * @property {number} [zoom] - The zoom for PDF forms. - */ + /** + * Determines if this form should submit the API on submit. + * @type {boolean} + */ + this.nosubmit = false; + + /** + * Determines if the form has tried to be submitted, error or not. + * @type {boolean} + */ + this.submitted = false; + + /** + * Determines if the form is being submitted at the moment. + * @type {boolean} + */ + this.submitting = false; + + /** + * The Formio instance for this form. + * @type {Formio} + */ + this.formio = null; + + /** + * The loader HTML element. + * @type {HTMLElement} + */ + this.loader = null; + + /** + * The alert HTML element + * @type {HTMLElement} + */ + this.alert = null; -/** - * Renders a Form.io form within the webpage. - */ -export default class Webform extends NestedDataComponent { - /** - * @type {FormOptions} - the options for this Webform. - */ - options; + /** + * Promise that is triggered when the submission is done loading. + * @type {Promise} + */ + this.onSubmission = null; + + /** + * Determines if this submission is explicitly set. + * @type {boolean} + */ + this.submissionSet = false; + + /** + * Promise that executes when the form is ready and rendered. + * @type {Promise} + * @example + * import Webform from '@formio/js/Webform'; + * let form = new Webform(document.getElementById('formio')); + * form.formReady.then(() => { + * console.log('The form is ready!'); + * }); + * form.src = 'https://examples.form.io/example'; + */ + this.formReady = new Promise((resolve, reject) => { + /** + * Called when the formReady state of this form has been resolved. + * @type {Function} + */ + this.formReadyResolve = resolve; + + /** + * Called when this form could not load and is rejected. + * @type {Function} + */ + this.formReadyReject = reject; + }); - /** - * Creates a new Form instance. - * - * @param {HTMLElement | Object | FormOptions} [elementOrOptions] - The DOM element to render this form within or the options to create this form instance. - * @param {FormOptions} [options] - The options to create a new form instance. - */ - constructor(elementOrOptions, options) { - let element, formOptions; - if (elementOrOptions instanceof HTMLElement || options) { - element = elementOrOptions; - formOptions = options; + /** + * Promise that executes when the submission is ready and rendered. + * @type {Promise} + * @example + * import Webform from '@formio/js/Webform'; + * let form = new Webform(document.getElementById('formio')); + * form.submissionReady.then(() => { + * console.log('The submission is ready!'); + * }); + * form.src = 'https://examples.form.io/example/submission/234234234234234243'; + */ + this.submissionReady = new Promise((resolve, reject) => { + /** + * Called when the formReady state of this form has been resolved. + * @type {Function} + */ + this.submissionReadyResolve = resolve; + + /** + * Called when this form could not load and is rejected. + * @type {Function} + */ + this.submissionReadyReject = reject; + }); + + this.shortcuts = []; + + // Set language after everything is established. + this.language = this.i18next.language; + + // See if we need to restore the draft from a user. + if (this.options.saveDraft && !this.options.skipDraftRestore) { + this.formReady.then(() => { + const user = Formio.getUser(); + // Only restore a draft if the submission isn't explicitly set. + if (user && !this.submissionSet) { + this.restoreDraft(user._id); + } + }); + } + + this.component.clearOnHide = false; + + // Ensure the root is set to this component. + this.root = this; + this.localRoot = this; } - else { - formOptions = elementOrOptions; + /* eslint-enable max-statements */ + + get language() { + return this.options.language; } - super(null, getOptions(formOptions)); - this.setElement(element); + get emptyValue() { + return null; + } - // Keep track of all available forms globally. - Formio.forms[this.id] = this; + componentContext() { + return this._data; + } - // Set the base url. - if (this.options.baseUrl) { - Formio.setBaseUrl(this.options.baseUrl); + /** + * Sets the language for this form. + * @param {string} lang - The language to use (e.g. 'en', 'sp', etc.) + */ + set language(lang) { + if (!this.i18next) { + return; + } + this.options.language = lang; + if (this.i18next.language === lang) { + return; + } + this.i18next.changeLanguage(lang, (err) => { + if (err) { + return; + } + this.rebuild(); + this.emit("languageChanged"); + }); + } + + get componentComponents() { + return this.form.components; + } + + get shadowRoot() { + return this.options.shadowRoot; } /** - * The type of this element. - * @type {string} + * Add a language for translations + * @param {string} code - The language code for the language being added. + * @param {object} lang - The language translations. + * @param {boolean} [active] - If this language should be set as the active language. */ - this.type = 'form'; - this._src = ''; - this._loading = false; - this._form = {}; - this.draftEnabled = false; - this.savingDraft = true; - if (this.options.saveDraftThrottle) { - this.triggerSaveDraft = _.throttle(this.saveDraft.bind(this), this.options.saveDraftThrottle); + addLanguage(code, lang, active = false) { + if (this.i18next) { + var translations = _.assign(fastCloneDeep(i18nDefaults.resources.en.translation), lang); + this.i18next.addResourceBundle(code, "translation", translations, true, true); + if (active) { + this.language = code; + } + } + } + + keyboardCatchableElement(element) { + if (element.nodeName === "TEXTAREA") { + return false; + } + + if (element.nodeName === "INPUT") { + return ["text", "email", "password"].indexOf(element.type) === -1; + } + + return true; + } + + executeShortcuts = (event) => { + const { target } = event; + if (!this.keyboardCatchableElement(target)) { + return; + } + + const ctrl = event.ctrlKey || event.metaKey; + const keyCode = event.keyCode; + let char = ""; + + if (65 <= keyCode && keyCode <= 90) { + char = String.fromCharCode(keyCode); + } else if (keyCode === 13) { + char = "Enter"; + } else if (keyCode === 27) { + char = "Esc"; + } + + _.each(this.shortcuts, (shortcut) => { + if (shortcut.ctrl && !ctrl) { + return; + } + + if (shortcut.shortcut === char) { + shortcut.element.click(); + event.preventDefault(); + } + }); + }; + + addShortcut(element, shortcut) { + if (!shortcut || !/^([A-Z]|Enter|Esc)$/i.test(shortcut)) { + return; + } + + shortcut = _.capitalize(shortcut); + + if (shortcut === "Enter" || shortcut === "Esc") { + // Restrict Enter and Esc only for buttons + if (element.tagName !== "BUTTON") { + return; + } + + this.shortcuts.push({ + shortcut, + element, + }); + } else { + this.shortcuts.push({ + ctrl: true, + shortcut, + element, + }); + } } - else { - this.triggerSaveDraft = this.saveDraft.bind(this); + + removeShortcut(element, shortcut) { + if (!shortcut || !/^([A-Z]|Enter|Esc)$/i.test(shortcut)) { + return; + } + + _.remove(this.shortcuts, { + shortcut, + element, + }); } /** - * Determines if this form should submit the API on submit. - * @type {boolean} + * Get the embed source of the form. + * @returns {string} - The source of the form. */ - this.nosubmit = false; + get src() { + return this._src; + } /** - * Determines if the form has tried to be submitted, error or not. - * - * @type {boolean} + * Loads the submission if applicable. + * @returns {Promise} - The promise that is triggered when the submission is loaded. */ - this.submitted = false; + loadSubmission() { + this.loadingSubmission = true; + if (this.formio.submissionId) { + this.onSubmission = this.formio + .loadSubmission() + .then( + (submission) => this.setSubmission(submission), + (err) => this.submissionReadyReject(err) + ) + .catch((err) => this.submissionReadyReject(err)); + } else { + this.submissionReadyResolve(); + } + return this.submissionReady; + } /** - * Determines if the form is being submitted at the moment. - * - * @type {boolean} + * Set the src of the form renderer. + * @param {string} value - The source value to set. + * @param {any} options - The options to set. + * @returns {Promise} - The promise that is triggered when the form is set. + */ + setSrc(value, options) { + if (this.setUrl(value, options)) { + this.nosubmit = false; + return this.formio + .loadForm({ params: { live: 1 } }) + .then((form) => { + const setForm = this.setForm(form); + this.loadSubmission(); + return setForm; + }) + .catch((err) => { + console.warn(err); + this.formReadyReject(err); + }); + } + return Promise.resolve(); + } + + /** + * Set the Form source, which is typically the Form.io embed URL. + * @param {string} value - The value of the form embed url. + * @example + * import Webform from '@formio/js/Webform'; + * let form = new Webform(document.getElementById('formio')); + * form.formReady.then(() => { + * console.log('The form is formReady!'); + * }); + * form.src = 'https://examples.form.io/example'; */ - this.submitting = false; + set src(value) { + this.setSrc(value); + } /** - * The Formio instance for this form. - * @type {Formio} + * Get the embed source of the form. + * @returns {string} - returns the source of the form. */ - this.formio = null; + get url() { + return this._src; + } /** - * The loader HTML element. - * @type {HTMLElement} + * Sets the url of the form renderer. + * @param {string} value - The value to set the url to. + * @param {any} options - The options to set. + * @returns {boolean} - TRUE means the url was set, FALSE otherwise. */ - this.loader = null; + setUrl(value, options) { + if (!value || typeof value !== "string" || value === this._src) { + return false; + } + this._src = value; + this.nosubmit = true; + this.formio = this.options.formio = new Formio(value, options); + + if (this.type === "form") { + // Set the options source so this can be passed to other components. + this.options.src = value; + } + return true; + } /** - * The alert HTML element - * @type {HTMLElement} + * Set the form source but don't initialize the form and submission from the url. + * @param {string} value - The value of the form embed url. */ - this.alert = null; + set url(value) { + this.setUrl(value); + } /** - * Promise that is triggered when the submission is done loading. - * @type {Promise} + * Called when both the form and submission have been loaded. + * @returns {Promise} - The promise to trigger when both form and submission have loaded. */ - this.onSubmission = null; + get ready() { + return this.formReady.then(() => { + return super.ready.then(() => { + return this.loadingSubmission ? this.submissionReady : true; + }); + }); + } /** - * Determines if this submission is explicitly set. - * @type {boolean} + * Returns if this form is loading. + * @returns {boolean} - TRUE means the form is loading, FALSE otherwise. */ - this.submissionSet = false; + get loading() { + return this._loading; + } /** - * Promise that executes when the form is ready and rendered. - * @type {Promise} - * - * @example - * import Webform from '@formio/js/Webform'; - * let form = new Webform(document.getElementById('formio')); - * form.formReady.then(() => { - * console.log('The form is ready!'); - * }); - * form.src = 'https://examples.form.io/example'; + * Set the loading state for this form, and also show the loader spinner. + * @param {boolean} loading - If this form should be "loading" or not. */ - this.formReady = new Promise((resolve, reject) => { - /** - * Called when the formReady state of this form has been resolved. - * - * @type {function} - */ - this.formReadyResolve = resolve; - - /** - * Called when this form could not load and is rejected. - * - * @type {function} - */ - this.formReadyReject = reject; - }); + set loading(loading) { + if (this._loading !== loading) { + this._loading = loading; + if (!this.loader && loading) { + this.loader = this.ce("div", { + class: "loader-wrapper", + }); + const spinner = this.ce("div", { + class: "loader text-center", + }); + this.loader.appendChild(spinner); + } + /* eslint-disable max-depth */ + if (this.loader) { + try { + if (loading) { + this.prependTo(this.loader, this.wrapper); + } else { + this.removeChildFrom(this.loader, this.wrapper); + } + } catch (err) { + // ingore + } + } + /* eslint-enable max-depth */ + } + } /** - * Promise that executes when the submission is ready and rendered. - * @type {Promise} - * + * Sets the JSON schema for the form to be rendered. * @example * import Webform from '@formio/js/Webform'; * let form = new Webform(document.getElementById('formio')); - * form.submissionReady.then(() => { - * console.log('The submission is ready!'); + * form.setForm({ + * components: [ + * { + * type: 'textfield', + * key: 'firstName', + * label: 'First Name', + * placeholder: 'Enter your first name.', + * input: true + * }, + * { + * type: 'textfield', + * key: 'lastName', + * label: 'Last Name', + * placeholder: 'Enter your last name', + * input: true + * }, + * { + * type: 'button', + * action: 'submit', + * label: 'Submit', + * theme: 'primary' + * } + * ] * }); - * form.src = 'https://examples.form.io/example/submission/234234234234234243'; + * @param {object} form - The JSON schema of the form @see https://examples.form.io/example for an example JSON schema. + * @param {any} flags - Any flags to apply when setting the form. + * @returns {Promise} - The promise that is triggered when the form is set. */ - this.submissionReady = new Promise((resolve, reject) => { - /** - * Called when the formReady state of this form has been resolved. - * - * @type {function} - */ - this.submissionReadyResolve = resolve; - - /** - * Called when this form could not load and is rejected. - * - * @type {function} - */ - this.submissionReadyReject = reject; - }); + setForm(form, flags) { + const isFormAlreadySet = this._form && this._form.components?.length; + try { + // Do not set the form again if it has been already set + if (isFormAlreadySet && JSON.stringify(this._form) === JSON.stringify(form)) { + return Promise.resolve(); + } - this.shortcuts = []; - - // Set language after everything is established. - this.language = this.i18next.language; - - // See if we need to restore the draft from a user. - if (this.options.saveDraft) { - this.formReady.then(()=> { - if (!this.options.skipDraftRestore) { - const user = Formio.getUser(); - // Only restore a draft if the submission isn't explicitly set. - if (user && !this.submissionSet) { - this.restoreDraft(user._id); - } - } - else { - // Enable drafts - this.draftEnabled = true; - this.savingDraft = false; - } - }); - } - - this.component.clearOnHide = false; - - // Ensure the root is set to this component. - this.root = this; - this.localRoot = this; - } - /* eslint-enable max-statements */ - - get language() { - return this.options.language; - } - - get emptyValue() { - return null; - } - - componentContext() { - return this._data; - } - - /** - * Sets the language for this form. - * - * @param lang - * @return {Promise} - */ - set language(lang) { - if (!this.i18next) { - return; - } - this.options.language = lang; - if (this.i18next.language === lang) { - return; - } - this.i18next.changeLanguage(lang, (err) => { - if (err) { - return; - } - this.rebuild(); - this.emit('languageChanged'); - }); - } + // Create the form. + this._form = flags?.keepAsReference ? form : _.cloneDeep(form); + + if (this.onSetForm) { + this.onSetForm(_.cloneDeep(this._form), form); + } + + if (this.parent?.component?.modalEdit) { + return Promise.resolve(); + } + } catch (err) { + console.warn(err); + // If provided form is not a valid JSON object, do not set it too + return Promise.resolve(); + } + + // Allow the form to provide component overrides. + if (form && form.settings && form.settings.components) { + this.options.components = form.settings.components; + } + + if (form && form.properties) { + this.options.properties = form.properties; + } + // Use the sanitize config from the form settings or the global sanitize config if it is not provided in the options + if (!this.options.sanitizeConfig && !this.builderMode) { + this.options.sanitizeConfig = + _.get(form, "settings.sanitizeConfig") || + _.get(form, "globalSettings.sanitizeConfig"); + } - get componentComponents() { - return this.form.components; - } + if ("schema" in form && compareVersions(form.schema, "1.x") > 0) { + this.ready.then(() => { + this.setAlert( + "alert alert-danger", + "Form schema is for a newer version, please upgrade your renderer. Some functionality may not work." + ); + }); + } - get shadowRoot() { - return this.options.shadowRoot; - } + // See if they pass a module, and evaluate it if so. + if (form && form.module) { + let formModule = null; + if (typeof form.module === "string") { + try { + formModule = this.evaluate(`return ${form.module}`); + } catch (err) { + console.warn(err); + } + } else { + formModule = form.module; + } + if (formModule) { + Formio.use(formModule); - /** - * Add a language for translations - * - * @param code - * @param lang - * @param active - * @return {*} - */ - addLanguage(code, lang, active = false) { - if (this.i18next) { - var translations = _.assign(fastCloneDeep(i18nDefaults.resources.en.translation), lang); - this.i18next.addResourceBundle(code, 'translation', translations, true, true); - if (active) { - this.language = code; - } + // Since we got here after instantiation, we need to manually apply form options. + if (formModule.options && formModule.options.form) { + this.options = Object.assign(this.options, formModule.options.form); + } + } + } + + this.initialized = false; + const rebuild = this.rebuild() || Promise.resolve(); + return rebuild.then(() => { + this.emit("formLoad", form); + this.triggerRecaptcha(); + // Make sure to trigger onChange after a render event occurs to speed up form rendering. + setTimeout(() => { + this.onChange(flags); + this.formReadyResolve(); + }, 0); + + return this.formReady; + }); } - } - keyboardCatchableElement(element) { - if (element.nodeName === 'TEXTAREA') { - return false; + /** + * Gets the form object. + * @returns {object} - The form JSON schema. + */ + get form() { + if (!this._form) { + this._form = { + components: [], + }; + } + return this._form; } - if (element.nodeName === 'INPUT') { - return [ - 'text', - 'email', - 'password' - ].indexOf(element.type) === -1; + /** + * Sets the form value. + * @alias setForm + * @param {object} form - The form schema object. + */ + set form(form) { + this.setForm(form); } - return true; - } + /** + * Returns the submission object that was set within this form. + * @returns {object} - The submission object. + */ + get submission() { + return this.getValue(); + } - executeShortcuts = (event) => { - const { target } = event; - if (!this.keyboardCatchableElement(target)) { - return; + /** + * Sets the submission of a form. + * @example + * import Webform from '@formio/js/Webform'; + * let form = new Webform(document.getElementById('formio')); + * form.src = 'https://examples.form.io/example'; + * form.submission = {data: { + * firstName: 'Joe', + * lastName: 'Smith', + * email: 'joe@example.com' + * }}; + * @param {object} submission - The Form.io submission object. + */ + set submission(submission) { + this.setSubmission(submission); } - const ctrl = event.ctrlKey || event.metaKey; - const keyCode = event.keyCode; - let char = ''; + /** + * Sets a submission and returns the promise when it is ready. + * @param {any} submission - The submission to set. + * @param {any} flags - Any flags to apply when setting the submission. + * @returns {Promise} - The promise that is triggered when the submission is set. + */ + setSubmission(submission, flags = {}) { + flags = { + ...flags, + fromSubmission: _.has(flags, "fromSubmission") ? flags.fromSubmission : true, + }; + return (this.onSubmission = this.formReady + .then( + (resolveFlags) => { + if (resolveFlags) { + flags = { + ...flags, + ...resolveFlags, + }; + } + this.submissionSet = true; + this.triggerChange(flags); + this.emit("beforeSetSubmission", submission); + this.setValue(submission, flags); + return this.submissionReadyResolve(submission); + }, + (err) => this.submissionReadyReject(err) + ) + .catch((err) => this.submissionReadyReject(err))); + } + + handleDraftError(errName, errDetails, restoreDraft) { + const errorMessage = _.trim(`${this.t(errName)} ${errDetails || ""}`); + console.warn(errorMessage); + this.emit( + restoreDraft ? "restoreDraftError" : "saveDraftError", + errDetails || errorMessage + ); + } + + saveDraft() { + if (!this.draftEnabled) { + return; + } + if (!this.formio) { + this.handleDraftError("saveDraftInstanceError"); + return; + } + if (!Formio.getUser()) { + this.handleDraftError("saveDraftAuthError"); + return; + } + const draft = fastCloneDeep(this.submission); + draft.state = "draft"; + + if (!this.savingDraft) { + this.emit("saveDraftBegin"); + this.savingDraft = true; + this.formio + .saveSubmission(draft) + .then((sub) => { + // Set id to submission to avoid creating new draft submission + this.submission._id = sub._id; + this.savingDraft = false; + this.emit("saveDraft", sub); + }) + .catch((err) => { + this.savingDraft = false; + this.handleDraftError("saveDraftError", err); + }); + } + } - if (65 <= keyCode && keyCode <= 90) { - char = String.fromCharCode(keyCode); + /** + * Restores a draft submission based on the user who is authenticated. + * @param {string} userId - The user id where we need to restore the draft from. + */ + restoreDraft(userId) { + const formio = this.formio || this.options.formio; + if (!formio) { + this.handleDraftError("restoreDraftInstanceError", null, true); + return; + } + this.savingDraft = true; + formio + .loadSubmissions({ + params: { + state: "draft", + owner: userId, + }, + }) + .then((submissions) => { + if (submissions.length > 0 && !this.options.skipDraftRestore) { + const draft = fastCloneDeep(submissions[0]); + return this.setSubmission(draft).then(() => { + this.draftEnabled = true; + this.savingDraft = false; + this.emit("restoreDraft", draft); + }); + } + // Enable drafts so that we can keep track of changes. + this.draftEnabled = true; + this.savingDraft = false; + this.emit("restoreDraft", null); + }) + .catch((err) => { + this.draftEnabled = true; + this.savingDraft = false; + this.handleDraftError("restoreDraftError", err, true); + }); } - else if (keyCode === 13) { - char = 'Enter'; + + get schema() { + const schema = fastCloneDeep(_.omit(this._form, ["components"])); + schema.components = []; + this.eachComponent((component) => schema.components.push(component.schema)); + return schema; } - else if (keyCode === 27) { - char = 'Esc'; + + mergeData(_this, _that) { + _.mergeWith(_this, _that, (thisValue, thatValue) => { + if ( + Array.isArray(thisValue) && + Array.isArray(thatValue) && + thisValue.length !== thatValue.length + ) { + return thatValue; + } + }); } - _.each(this.shortcuts, (shortcut) => { - if (shortcut.ctrl && !ctrl) { - return; - } + setValue(submission, flags = {}) { + if (!submission || !submission.data) { + submission = { + data: {}, + metadata: submission.metadata, + }; + } + // Metadata needs to be available before setValue + this._submission.metadata = submission.metadata || {}; + this.editing = !!submission._id; + + // Set the timezone in the options if available. + if ( + !this.options.submissionTimezone && + submission.metadata && + submission.metadata.timezone + ) { + this.options.submissionTimezone = submission.metadata.timezone; + } - if (shortcut.shortcut === char) { - shortcut.element.click(); - event.preventDefault(); - } - }); - }; + const changed = super.setValue(submission.data, flags); + if (!flags.sanitize) { + this.mergeData(this.data, submission.data); + } + + submission.data = this.data; + this._submission = submission; + return changed; + } - addShortcut(element, shortcut) { - if (!shortcut || !/^([A-Z]|Enter|Esc)$/i.test(shortcut)) { - return; + getValue() { + if (!this._submission.data) { + this._submission.data = {}; + } + if (this.viewOnly) { + return this._submission; + } + const submission = this._submission; + submission.data = this.data; + return this._submission; } - shortcut = _.capitalize(shortcut); + /** + * Build the form. + * @returns {Promise} - The promise that is triggered when the form is built. + */ + init() { + if (this.options.submission) { + const submission = _.extend({}, this.options.submission); + this._submission = submission; + this._data = submission.data; + } else { + this._submission = this._submission || { data: {} }; + } + + // Remove any existing components. + if (this.components && this.components.length) { + this.destroyComponents(); + this.components = []; + } + + if (this.component) { + this.component.components = this.form ? this.form.components : []; + } else { + this.component = this.form; + } + this.component.type = "form"; + this.component.input = false; + + this.addComponents(); + this.on( + "submitButton", + (options) => { + this.submit(false, options).catch((e) => { + options.instance.loading = false; + return e !== false && e !== undefined && console.log(e); + }); + }, + true + ); + + this.on( + "checkValidity", + (data) => this.validate(data, { dirty: true, process: "change" }), + true + ); + this.on("requestUrl", (args) => this.submitUrl(args.url, args.headers), true); + this.on("resetForm", () => this.resetValue(), true); + this.on("deleteSubmission", () => this.deleteSubmission(), true); + this.on("refreshData", () => this.updateValue(), true); + + this.executeFormController(); + + return this.formReady; + } + + executeFormController() { + // If no controller value or + // hidden and set to clearOnHide (Don't calculate a value for a hidden field set to clear when hidden) + if ( + !this.form || + !this.form.controller || + ((!this.visible || this.component.hidden) && + this.component.clearOnHide && + !this.rootPristine) + ) { + return false; + } - if (shortcut === 'Enter' || shortcut === 'Esc') { - // Restrict Enter and Esc only for buttons - if (element.tagName !== 'BUTTON') { - return; - } + this.formReady.then(() => { + this.evaluate(this.form.controller, { + components: this.components, + instance: this, + }); + }); + } - this.shortcuts.push({ - shortcut, - element - }); + /** + * + */ + teardown() { + this.emit("formDelete", this.id); + delete Formio.forms[this.id]; + delete this.executeShortcuts; + delete this.triggerSaveDraft; + super.teardown(); + } + + destroy(all = false) { + this.off("submitButton"); + this.off("checkValidity"); + this.off("requestUrl"); + this.off("resetForm"); + this.off("deleteSubmission"); + this.off("refreshData"); + + return super.destroy(all); + } + + build(element) { + if (element || this.element) { + return this.ready.then(() => { + element = element || this.element; + super.build(element); + }); + } + return this.ready; } - else { - this.shortcuts.push({ - ctrl: true, - shortcut, - element - }); + + getClassName() { + let classes = "formio-form"; + if (this.options.readOnly) { + classes += " formio-read-only"; + } + return classes; } - } - removeShortcut(element, shortcut) { - if (!shortcut || !/^([A-Z]|Enter|Esc)$/i.test(shortcut)) { - return; + render() { + return super.render( + this.renderTemplate("webform", { + classes: this.getClassName(), + children: this.renderComponents(), + }), + this.builderMode ? "builder" : "form", + true + ); } - _.remove(this.shortcuts, { - shortcut, - element - }); - } - - /** - * Get the embed source of the form. - * - * @returns {string} - */ - get src() { - return this._src; - } - - /** - * Loads the submission if applicable. - */ - loadSubmission() { - this.loadingSubmission = true; - if (this.formio.submissionId) { - this.onSubmission = this.formio.loadSubmission().then( - (submission) => this.setSubmission(submission), - (err) => this.submissionReadyReject(err) - ).catch( - (err) => this.submissionReadyReject(err) - ); - } - else { - this.submissionReadyResolve(); - } - return this.submissionReady; - } - - /** - * Set the src of the form renderer. - * - * @param value - * @param options - */ - setSrc(value, options) { - if (this.setUrl(value, options)) { - this.nosubmit = false; - return this.formio.loadForm({ params: { live: 1 } }).then( - (form) => { - const setForm = this.setForm(form); - this.loadSubmission(); - return setForm; - }).catch((err) => { - console.warn(err); - this.formReadyReject(err); - }); - } - return Promise.resolve(); - } - - /** - * Set the Form source, which is typically the Form.io embed URL. - * - * @param {string} value - The value of the form embed url. - * - * @example - * import Webform from '@formio/js/Webform'; - * let form = new Webform(document.getElementById('formio')); - * form.formReady.then(() => { - * console.log('The form is formReady!'); - * }); - * form.src = 'https://examples.form.io/example'; - */ - set src(value) { - this.setSrc(value); - } - - /** - * Get the embed source of the form. - * - * @returns {string} - */ - get url() { - return this._src; - } - - /** - * Sets the url of the form renderer. - * - * @param value - * @param options - */ - setUrl(value, options) { - if ( - !value || - (typeof value !== 'string') || - (value === this._src) - ) { - return false; - } - this._src = value; - this.nosubmit = true; - this.formio = this.options.formio = new Formio(value, options); - - if (this.type === 'form') { - // Set the options source so this can be passed to other components. - this.options.src = value; - } - return true; - } - - /** - * Set the form source but don't initialize the form and submission from the url. - * - * @param {string} value - The value of the form embed url. - */ - set url(value) { - this.setUrl(value); - } - - /** - * Called when both the form and submission have been loaded. - * - * @returns {Promise} - The promise to trigger when both form and submission have loaded. - */ - get ready() { - return this.formReady.then(() => { - return super.ready.then(() => { - return this.loadingSubmission ? this.submissionReady : true; - }); - }); - } - - /** - * Returns if this form is loading. - * - * @returns {boolean} - TRUE means the form is loading, FALSE otherwise. - */ - get loading() { - return this._loading; - } - - /** - * Set the loading state for this form, and also show the loader spinner. - * - * @param {boolean} loading - If this form should be "loading" or not. - */ - set loading(loading) { - if (this._loading !== loading) { - this._loading = loading; - if (!this.loader && loading) { - this.loader = this.ce('div', { - class: 'loader-wrapper' - }); - const spinner = this.ce('div', { - class: 'loader text-center' + redraw() { + // Don't bother if we have not built yet. + if (!this.element) { + return Promise.resolve(); + } + this.clear(); + this.setContent(this.element, this.render()); + return this.attach(this.element); + } + + attach(element) { + this.setElement(element); + this.loadRefs(element, { webform: "single" }); + const childPromise = this.attachComponents(this.refs.webform); + this.addEventListener(document, "keydown", this.executeShortcuts); + this.currentForm = this; + this.hook("attachWebform", element, this); + return childPromise.then(() => { + this.emit("render", this.element); + + return this.setValue(this._submission, { + noUpdateEvent: true, + }); }); - this.loader.appendChild(spinner); - } - /* eslint-disable max-depth */ - if (this.loader) { - try { - if (loading) { - this.prependTo(this.loader, this.wrapper); - } - else { - this.removeChildFrom(this.loader, this.wrapper); - } - } - catch (err) { - // ingore - } - } - /* eslint-enable max-depth */ - } - } - - /** - * Sets the JSON schema for the form to be rendered. - * - * @example - * import Webform from '@formio/js/Webform'; - * let form = new Webform(document.getElementById('formio')); - * form.setForm({ - * components: [ - * { - * type: 'textfield', - * key: 'firstName', - * label: 'First Name', - * placeholder: 'Enter your first name.', - * input: true - * }, - * { - * type: 'textfield', - * key: 'lastName', - * label: 'Last Name', - * placeholder: 'Enter your last name', - * input: true - * }, - * { - * type: 'button', - * action: 'submit', - * label: 'Submit', - * theme: 'primary' - * } - * ] - * }); - * - * @param {Object} form - The JSON schema of the form @see https://examples.form.io/example for an example JSON schema. - * @param flags - * @returns {*} - */ - setForm(form, flags) { - const isFormAlreadySet = this._form && this._form.components?.length; - try { - // Do not set the form again if it has been already set - if (isFormAlreadySet && JSON.stringify(this._form) === JSON.stringify(form)) { - return Promise.resolve(); - } + } - // Create the form. - this._form = flags?.keepAsReference ? form : _.cloneDeep(form); + hasRequiredFields() { + let result = false; - if (this.onSetForm) { - this.onSetForm(_.cloneDeep(this._form), form); - } + eachComponent( + this.form.components, + (component) => { + if (component.validate.required) { + result = true; + return true; + } + }, + true + ); - if (this.parent?.component?.modalEdit) { - return Promise.resolve(); - } - } - catch (err) { - console.warn(err); - // If provided form is not a valid JSON object, do not set it too - return Promise.resolve(); + return result; } - // Allow the form to provide component overrides. - if (form && form.settings && form.settings.components) { - this.options.components = form.settings.components; + resetValue() { + _.each(this.getComponents(), (comp) => comp.resetValue()); + this.setPristine(true); + this.onChange({ resetValue: true }); } - if (form && form.properties) { - this.options.properties = form.properties; - } - // Use the sanitize config from the form settings or the global sanitize config if it is not provided in the options - if (!this.options.sanitizeConfig && !this.builderMode) { - this.options.sanitizeConfig = _.get(form, 'settings.sanitizeConfig') || _.get(form, 'globalSettings.sanitizeConfig'); - } + /** + * Sets a new alert to display in the error dialog of the form. + * @param {string} type - The type of alert to display. "danger", "success", "warning", etc. + * @param {string} message - The message to show in the alert. + * @param {object} options - The options for the alert. + */ + setAlert(type, message, options) { + if (!type && this.submitted) { + if (this.alert) { + if (this.refs.errorRef && this.refs.errorRef.length) { + this.refs.errorRef.forEach((el) => { + this.removeEventListener(el, "click"); + this.removeEventListener(el, "keypress"); + }); + } + this.removeChild(this.alert); + this.alert = null; + } + return; + } + if (this.options.noAlerts) { + if (!message) { + this.emit("error", false); + } + return; + } + if (this.alert) { + try { + if (this.refs.errorRef && this.refs.errorRef.length) { + this.refs.errorRef.forEach((el) => { + this.removeEventListener(el, "click"); + this.removeEventListener(el, "keypress"); + }); + } + this.removeChild(this.alert); + this.alert = null; + } catch (err) { + // ignore + } + } + if (message) { + const attrs = { + class: (options && options.classes) || `alert alert-${type}`, + id: `error-list-${this.id}`, + }; + + const templateOptions = { + message: message instanceof HTMLElement ? message.outerHTML : message, + attrs: attrs, + type, + }; + + this.alert = convertStringToHTMLElement( + this.renderTemplate("alert", templateOptions), + `#${attrs.id}` + ); + } + if (!this.alert) { + return; + } + + this.loadRefs(this.alert, { errorRef: "multiple" }); - if ('schema' in form && compareVersions(form.schema, '1.x') > 0) { - this.ready.then(() => { - this.setAlert('alert alert-danger', 'Form schema is for a newer version, please upgrade your renderer. Some functionality may not work.'); - }); + if (this.refs.errorRef && this.refs.errorRef.length) { + this.refs.errorRef.forEach((el) => { + this.addEventListener(el, "click", (e) => { + const key = e.currentTarget.dataset.componentKey; + this.focusOnComponent(key); + }); + this.addEventListener(el, "keydown", (e) => { + if (e.keyCode === 13) { + e.preventDefault(); + const key = e.currentTarget.dataset.componentKey; + this.focusOnComponent(key); + } + }); + }); + } + this.prepend(this.alert); } - // See if they pass a module, and evaluate it if so. - if (form && form.module) { - let formModule = null; - if (typeof form.module === 'string') { - try { - formModule = this.evaluate(`return ${form.module}`); + /** + * Focus on selected component. + * @param {string} key - The key of selected component. + */ + focusOnComponent(key) { + if (key) { + const component = this.getComponent(key); + if (component) { + component.focus(); + } } - catch (err) { - console.warn(err); + } + + /** + * Show the errors of this form within the alert dialog. + * @param {object} error - An optional additional error to display along with the component errors. + * @returns {*} + */ + /* eslint-disable no-unused-vars */ + /** + * + * @param {Array} errors - An array of errors to display. + * @param {boolean} triggerEvent - Whether or not to trigger the error event. + * @returns {void|Array} - The errors that were set. + */ + showErrors(errors, triggerEvent) { + this.loading = false; + if (!Array.isArray(errors)) { + errors = [errors]; } - } - else { - formModule = form.module; - } - if (formModule) { - Formio.use(formModule); - // Since we got here after instantiation, we need to manually apply form options. - if (formModule.options && formModule.options.form) { - this.options = Object.assign(this.options, formModule.options.form); + errors = errors.concat(this.customErrors).filter((err) => !!err); + + if (!errors.length) { + this.setAlert(false); + return; } - } - } - this.initialized = false; - const rebuild = this.rebuild() || Promise.resolve(); - return rebuild.then(() => { - this.emit('formLoad', form); - this.triggerRecaptcha(); - // Make sure to trigger onChange after a render event occurs to speed up form rendering. - setTimeout(() => { - this.onChange(flags); - this.formReadyResolve(); - }, 0); + // Mark any components as invalid if in a custom message. + errors.forEach((err) => { + const { components = [] } = err; - return this.formReady; - }); - } - - /** - * Gets the form object. - * - * @returns {Object} - The form JSON schema. - */ - get form() { - if (!this._form) { - this._form = { - components: [] - }; - } - return this._form; - } - - /** - * Sets the form value. - * - * @alias setForm - * @param {Object} form - The form schema object. - */ - set form(form) { - this.setForm(form); - } - - /** - * Returns the submission object that was set within this form. - * - * @returns {Object} - */ - get submission() { - return this.getValue(); - } - - /** - * Sets the submission of a form. - * - * @example - * import Webform from '@formio/js/Webform'; - * let form = new Webform(document.getElementById('formio')); - * form.src = 'https://examples.form.io/example'; - * form.submission = {data: { - * firstName: 'Joe', - * lastName: 'Smith', - * email: 'joe@example.com' - * }}; - * - * @param {Object} submission - The Form.io submission object. - */ - set submission(submission) { - this.setSubmission(submission); - } - - /** - * Sets a submission and returns the promise when it is ready. - * @param submission - * @param flags - * @return {Promise.} - */ - setSubmission(submission, flags = {}) { - flags = { - ...flags, - fromSubmission: _.has(flags, 'fromSubmission') ? flags.fromSubmission : true, - }; - return this.onSubmission = this.formReady.then( - (resolveFlags) => { - if (resolveFlags) { - flags = { - ...flags, - ...resolveFlags - }; - } - this.submissionSet = true; - this.triggerChange(flags); - this.emit('beforeSetSubmission', submission); - this.setValue(submission, flags); - return this.submissionReadyResolve(submission); - }, - (err) => this.submissionReadyReject(err) - ).catch( - (err) => this.submissionReadyReject(err) - ); - } - - handleDraftError(errName, errDetails, restoreDraft) { - const errorMessage = _.trim(`${this.t(errName)} ${errDetails || ''}`); - console.warn(errorMessage); - this.emit(restoreDraft ? 'restoreDraftError' : 'saveDraftError', errDetails || errorMessage); - } - - /** - * Saves a submission draft. - */ - saveDraft() { - if (!this.draftEnabled) { - return; - } - if (!this.formio) { - this.handleDraftError('saveDraftInstanceError'); - return; - } - if (!Formio.getUser()) { - this.handleDraftError('saveDraftAuthError'); - return; - } - const draft = fastCloneDeep(this.submission); - draft.state = 'draft'; - - if (!this.savingDraft && !this.submitting) { - this.emit('saveDraftBegin'); - this.savingDraft = true; - this.formio.saveSubmission(draft).then((sub) => { - // Set id to submission to avoid creating new draft submission - this.submission._id = sub._id; - this.savingDraft = false; - this.emit('saveDraft', sub); - }) - .catch(err => { - this.savingDraft = false; - this.handleDraftError('saveDraftError', err); - }); - } - } - - /** - * Restores a draft submission based on the user who is authenticated. - * - * @param {userId} - The user id where we need to restore the draft from. - */ - restoreDraft(userId) { - const formio = this.formio || this.options.formio; - if (!formio) { - this.handleDraftError('restoreDraftInstanceError', null, true); - return; - } - this.savingDraft = true; - formio.loadSubmissions({ - params: { - state: 'draft', - owner: userId - } - }).then(submissions => { - if (submissions.length > 0 && !this.options.skipDraftRestore) { - const draft = fastCloneDeep(submissions[0]); - return this.setSubmission(draft).then(() => { - this.draftEnabled = true; - this.savingDraft = false; - this.emit('restoreDraft', draft); - }); - } - // Enable drafts so that we can keep track of changes. - this.draftEnabled = true; - this.savingDraft = false; - this.emit('restoreDraft', null); - }) - .catch(err => { - this.draftEnabled = true; - this.savingDraft = false; - this.handleDraftError('restoreDraftError', err, true); - }); - } - - get schema() { - const schema = fastCloneDeep(_.omit(this._form, ['components'])); - schema.components = []; - this.eachComponent((component) => schema.components.push(component.schema)); - return schema; - } - - mergeData(_this, _that) { - _.mergeWith(_this, _that, (thisValue, thatValue) => { - if (Array.isArray(thisValue) && Array.isArray(thatValue) && thisValue.length !== thatValue.length) { - return thatValue; - } - }); - } + if (err.component) { + components.push(err.component); + } + + if (err.path) { + components.push(err.path); + } - setValue(submission, flags = {}) { - if (!submission || !submission.data) { - submission = { - data: {}, - metadata: submission.metadata, - }; - } - // Metadata needs to be available before setValue - this._submission.metadata = submission.metadata || {}; - this.editing = !!submission._id; - - // Set the timezone in the options if available. - if ( - !this.options.submissionTimezone && - submission.metadata && - submission.metadata.timezone - ) { - this.options.submissionTimezone = submission.metadata.timezone; - } - - const changed = super.setValue(submission.data, flags); - if (!flags.sanitize) { - this.mergeData(this.data, submission.data); - } - - submission.data = this.data; - this._submission = submission; - return changed; - } - - getValue() { - if (!this._submission.data) { - this._submission.data = {}; - } - if (this.viewOnly) { - return this._submission; - } - const submission = this._submission; - submission.data = this.data; - return this._submission; - } - - /** - * Build the form. - */ - init() { - if (this.options.submission) { - const submission = _.extend({}, this.options.submission); - this._submission = submission; - this._data = submission.data; - } - else { - this._submission = this._submission || { data: {} }; - } - - // Remove any existing components. - if (this.components && this.components.length) { - this.destroyComponents(); - this.components = []; - } - - if (this.component) { - this.component.components = this.form ? this.form.components : []; - } - else { - this.component = this.form; - } - this.component.type = 'form'; - this.component.input = false; - - this.addComponents(); - this.on('submitButton', options => { - this.submit(false, options).catch(e => { - options.instance.loading = false; - return e !== false && e !== undefined && console.log(e); - }); - }, true); - - this.on('checkValidity', (data) => this.validate(data, { dirty: true, process: 'change' }), true); - this.on('requestUrl', (args) => (this.submitUrl(args.url,args.headers)), true); - this.on('resetForm', () => this.resetValue(), true); - this.on('deleteSubmission', () => this.deleteSubmission(), true); - this.on('refreshData', () => this.updateValue(), true); - - this.executeFormController(); - - return this.formReady; - } - - executeFormController() { - // If no controller value or - // hidden and set to clearOnHide (Don't calculate a value for a hidden field set to clear when hidden) - if ( - !this.form || !this.form.controller - || ((!this.visible || this.component.hidden) && this.component.clearOnHide && !this.rootPristine) - ) { - return false; - } - - this.formReady.then(() => { - this.evaluate(this.form.controller, { - components: this.components, - instance: this, + components.forEach((path) => { + const originalPath = getStringFromComponentPath(path); + const component = this.getComponent(path, _.identity, originalPath); + + if (err.fromServer) { + if (component.serverErrors) { + component.serverErrors.push(err); + } else { + component.serverErrors = [err]; + } + } + const components = _.compact(Array.isArray(component) ? component : [component]); + + components.forEach((component) => component.setCustomValidity(err.message, true)); + }); }); - }); - } - - teardown() { - this.emit('formDelete', this.id); - delete Formio.forms[this.id]; - delete this.executeShortcuts; - delete this.triggerSaveDraft; - super.teardown(); - } - - destroy(all = false) { - this.off('submitButton'); - this.off('checkValidity'); - this.off('requestUrl'); - this.off('resetForm'); - this.off('deleteSubmission'); - this.off('refreshData'); - - return super.destroy(all); - } - - build(element) { - if (element || this.element) { - return this.ready.then(() => { - element = element || this.element; - super.build(element); - }); - } - return this.ready; - } - - getClassName() { - let classes = 'formio-form'; - if (this.options.readOnly) { - classes += ' formio-read-only'; - } - return classes; - } - - render() { - return super.render(this.renderTemplate('webform', { - classes: this.getClassName(), - children: this.renderComponents(), - }), this.builderMode ? 'builder' : 'form', true); - } - - redraw() { - // Don't bother if we have not built yet. - if (!this.element) { - return Promise.resolve(); - } - this.clear(); - this.setContent(this.element, this.render()); - return this.attach(this.element); - } - - attach(element) { - this.setElement(element); - this.loadRefs(element, { webform: 'single' }); - const childPromise = this.attachComponents(this.refs.webform); - this.addEventListener(document, 'keydown', this.executeShortcuts); - this.currentForm = this; - this.hook('attachWebform', element, this); - return childPromise.then(() => { - this.emit('render', this.element); - - return this.setValue(this._submission, { - noUpdateEvent: true, - }); - }); - } - hasRequiredFields() { - let result = false; + const displayedErrors = []; + if (errors.length) { + errors = _.uniqBy(errors, (error) => error.message); + const createListItem = (message, index) => { + const err = errors[index]; + const messageFromIndex = !_.isUndefined(index) && errors && errors[index]; + const keyOrPath = + messageFromIndex?.formattedKeyOrPath || + messageFromIndex?.path || + messageFromIndex?.context?.path || + (err.context?.component && err.context?.component.key) || + (err.component && err.component.key) || + (err.fromServer && err.path); + + const formattedKeyOrPath = keyOrPath ? getStringFromComponentPath(keyOrPath) : ""; + if (typeof err !== "string" && !err.formattedKeyOrPath) { + err.formattedKeyOrPath = formattedKeyOrPath; + } + + return { + message: unescapeHTML(message), + keyOrPath: formattedKeyOrPath, + }; + }; + + errors.forEach(({ message, context, fromServer, component }, index) => { + const text = + !component?.label || context?.hasLabel || fromServer + ? this.t("alertMessage", { message: this.t(message) }) + : this.t("alertMessageWithLabel", { + label: this.t(component?.label), + message: this.t(message), + }); + displayedErrors.push(createListItem(text, index)); + }); + } - eachComponent(this.form.components, (component) => { - if (component.validate.required) { - result = true; - return true; - } - }, true); - - return result; - } - - resetValue() { - _.each(this.getComponents(), (comp) => (comp.resetValue())); - this.setPristine(true); - this.onChange({ resetValue: true }); - } - - /** - * Sets a new alert to display in the error dialog of the form. - * - * @param {string} type - The type of alert to display. "danger", "success", "warning", etc. - * @param {string} message - The message to show in the alert. - * @param {Object} options - */ - setAlert(type, message, options) { - if (!type && this.submitted) { - if (this.alert) { - if (this.refs.errorRef && this.refs.errorRef.length) { - this.refs.errorRef.forEach(el => { - this.removeEventListener(el, 'click'); - this.removeEventListener(el, 'keypress'); - }); + const errorsList = this.renderTemplate("errorsList", { errors: displayedErrors }); + this.root.setAlert("danger", errorsList); + if (triggerEvent) { + this.emit("error", errors); } - this.removeChild(this.alert); - this.alert = null; - } - return; - } - if (this.options.noAlerts) { - if (!message) { - this.emit('error', false); - } - return; + + return errors; } - if (this.alert) { - try { - if (this.refs.errorRef && this.refs.errorRef.length) { - this.refs.errorRef.forEach(el => { - this.removeEventListener(el, 'click'); - this.removeEventListener(el, 'keypress'); - }); + /* eslint-enable no-unused-vars */ + + /** + * Called when the submission has completed, or if the submission needs to be sent to an external library. + * @param {object} submission - The submission object. + * @param {boolean} saved - Whether or not this submission was saved to the server. + * @returns {object} - The submission object. + */ + onSubmit(submission, saved) { + this.loading = false; + this.submitting = false; + this.setPristine(true); + // We want to return the submitted submission and setValue will mutate the submission so cloneDeep it here. + this.setValue(fastCloneDeep(submission), { + noValidate: true, + noCheck: true, + }); + this.setAlert("success", `

${this.t("complete")}

`); + // Cancel triggered saveDraft to prevent overriding the submitted state + if (this.draftEnabled && this.triggerSaveDraft?.cancel) { + this.triggerSaveDraft.cancel(); } - this.removeChild(this.alert); - this.alert = null; - } - catch (err) { - // ignore - } + this.emit("submit", submission, saved); + if (saved) { + this.emit("submitDone", submission); + } + return submission; } - if (message) { - const attrs = { - class: (options && options.classes) || `alert alert-${type}`, - id: `error-list-${this.id}`, - }; - const templateOptions = { - message: message instanceof HTMLElement ? message.outerHTML : message, - attrs: attrs, - type - }; + normalizeError(error) { + if (error) { + if (typeof error === "object" && "details" in error) { + error = error.details; + } - this.alert = convertStringToHTMLElement(this.renderTemplate('alert', templateOptions),`#${attrs.id}`); - } - if (!this.alert) { - return; + if (typeof error === "string") { + error = { message: error }; + } + } + + return error; } - this.loadRefs(this.alert, { errorRef: 'multiple' }); + /** + * Called when an error occurs during the submission. + * @param {object} error - The error that occured. + * @returns {Array} errors - All errors. + */ + onSubmissionError(error) { + error = this.normalizeError(error); - if (this.refs.errorRef && this.refs.errorRef.length) { - this.refs.errorRef.forEach(el => { - this.addEventListener(el, 'click', (e) => { - const key = e.currentTarget.dataset.componentKey; - this.focusOnComponent(key); - }); - this.addEventListener(el, 'keydown', (e) => { - if (e.keyCode === 13) { - e.preventDefault(); - const key = e.currentTarget.dataset.componentKey; - this.focusOnComponent(key); - } - }); - }); - } - this.prepend(this.alert); - } - - /** - * Focus on selected component. - * - * @param {string} key - The key of selected component. - * @returns {*} - */ - focusOnComponent(key) { - if (key) { - const component = this.getComponent(key); - if (component) { - component.focus(); - } - } - } - - /** - * Show the errors of this form within the alert dialog. - * - * @param {Object} error - An optional additional error to display along with the component errors. - * @returns {*} - */ - /* eslint-disable no-unused-vars */ - showErrors(errors, triggerEvent) { - this.loading = false; - if (!Array.isArray(errors)) { - errors = [errors]; - } - - errors = errors.concat(this.customErrors).filter((err) => !!err); - - if (!errors.length) { - this.setAlert(false); - return; - } - - // Mark any components as invalid if in a custom message. - errors.forEach((err) => { - const { components = [] } = err; - - if (err.component) { - components.push(err.component); - } - - if (err.path) { - components.push(err.path); - } - - components.forEach((path) => { - const originalPath = getStringFromComponentPath(path); - const component = this.getComponent(path, _.identity, originalPath); - - if (err.fromServer) { - if (component.serverErrors) { - component.serverErrors.push(err); - } - else { - component.serverErrors = [err]; - } - } - const components = _.compact(Array.isArray(component) ? component : [component]); - - components.forEach((component) => component.setCustomValidity(err.message, true)); - }); - }); + this.submitting = false; + this.setPristine(false); + this.emit("submitError", error || this.errors); + + // Allow for silent cancellations (no error message, no submit button error state) + if (error && error.silent) { + this.emit("change", { isValid: true }, { silent: true }); + return false; + } - const displayedErrors = []; - if (errors.length) { - errors = _.uniqBy(errors, error => error.message); - const createListItem = (message, index) => { - const err = errors[index]; - const messageFromIndex = !_.isUndefined(index) && errors && errors[index]; - const keyOrPath = (messageFromIndex?.formattedKeyOrPath || messageFromIndex?.path || messageFromIndex?.context?.path) || (err.context?.component && err.context?.component.key) || (err.component && err.component.key) || err.fromServer && err.path; + const errors = this.showErrors(error, true); - const formattedKeyOrPath = keyOrPath ? getStringFromComponentPath(keyOrPath) : ''; - if (typeof err !== 'string' && !err.formattedKeyOrPath) { - err.formattedKeyOrPath = formattedKeyOrPath; + if (this.root && this.root.alert) { + this.scrollIntoView(this.root.alert); } - return { - message: unescapeHTML(message), - keyOrPath: formattedKeyOrPath - }; - }; - - errors.forEach(({ message, context, fromServer, component }, index) => { - const text = !component?.label || context?.hasLabel || fromServer - ? this.t('alertMessage', { message: this.t(message) }) - : this.t('alertMessageWithLabel', { - label: this.t(component?.label), - message: this.t(message), - }); - displayedErrors.push(createListItem(text, index)); - }); - } - - const errorsList = this.renderTemplate('errorsList', { errors: displayedErrors }); - this.root.setAlert('danger', errorsList); - if (triggerEvent) { - this.emit('error', errors); - } - - return errors; - } - /* eslint-enable no-unused-vars */ - - /** - * Called when the submission has completed, or if the submission needs to be sent to an external library. - * - * @param {Object} submission - The submission object. - * @param {boolean} saved - Whether or not this submission was saved to the server. - * @returns {object} - The submission object. - */ - onSubmit(submission, saved) { - this.loading = false; - this.submitting = false; - this.setPristine(true); - // We want to return the submitted submission and setValue will mutate the submission so cloneDeep it here. - this.setValue(fastCloneDeep(submission), { - noValidate: true, - noCheck: true - }); - this.setAlert('success', `

${this.t('complete')}

`); - // Cancel triggered saveDraft to prevent overriding the submitted state - if (this.draftEnabled && this.triggerSaveDraft?.cancel) { - this.triggerSaveDraft.cancel(); + return errors; } - this.emit('submit', submission, saved); - if (saved) { - this.emit('submitDone', submission); - } - return submission; - } - normalizeError(error) { - if (error) { - if (typeof error === 'object' && 'details' in error) { - error = error.details; - } - - if (typeof error === 'string') { - error = { message: error }; - } - } - - return error; - } - - /** - * Called when an error occurs during the submission. - * - * @param {Object} error - The error that occured. - */ - onSubmissionError(error) { - error = this.normalizeError(error); - - this.submitting = false; - this.setPristine(false); - this.emit('submitError', error || this.errors); - - // Allow for silent cancellations (no error message, no submit button error state) - if (error && error.silent) { - this.emit('change', { isValid: true }, { silent: true }); - return false; - } - - const errors = this.showErrors(error, true); - - if (this.root && this.root.alert) { - this.scrollIntoView(this.root.alert); - } - - return errors; - } - - /** - * Trigger the change event for this form. - * - * @param changed - * @param flags - */ - onChange(flags, changed, modified, changes) { - flags = flags || {}; - let isChangeEventEmitted = false; - super.onChange(flags, true); - const value = _.clone(this.submission); - flags.changed = value.changed = changed; - flags.changes = changes; - - if (modified && this.pristine) { - this.pristine = false; - } - - this.checkData(value.data, flags); - const shouldValidate = !flags.noValidate || flags.fromIFrame || (flags.fromSubmission && this.rootPristine && this.pristine && flags.changed); - const errors = shouldValidate ? this.validate(value.data, { ...flags, process: 'change' }) : []; - value.isValid = errors.length === 0; - - this.loading = false; - if (this.submitted) { - // show server errors while they are not cleaned/fixed - const nonComponentServerErrors = _.filter(this.serverErrors || [], err => !err.component && !err.path); - this.showErrors(nonComponentServerErrors.length ? nonComponentServerErrors : errors); - } - - // See if we need to save the draft of the form. - if (modified && this.options.saveDraft) { - this.triggerSaveDraft(); - } - - if (!flags || !flags.noEmit) { - this.emit('change', value, flags, modified); - isChangeEventEmitted = true; - } - - // The form is initialized after the first change event occurs. - if (isChangeEventEmitted && !this.initialized) { - this.emit('initialized'); - this.initialized = true; - } - } - - /** - * Send a delete request to the server. - */ - deleteSubmission() { - return this.formio.deleteSubmission() - .then(() => { - this.emit('submissionDeleted', this.submission); - this.resetValue(); - }); - } - - /** - * Cancels the submission. - * - * @alias reset - */ - cancel(noconfirm) { - const shouldReset = this.hook('beforeCancel', true); - if (shouldReset && (noconfirm || confirm(this.t('confirmCancel')))) { - this.resetValue(); - return true; - } - else { - this.emit('cancelSubmit'); - return false; - } - } - - setMetadata(submission) { - // Add in metadata about client submitting the form - submission.metadata = submission.metadata || {}; - _.defaults(submission.metadata, { - timezone: _.get(this, '_submission.metadata.timezone', currentTimezone()), - offset: parseInt(_.get(this, '_submission.metadata.offset', moment().utcOffset()), 10), - origin: document.location.origin, - referrer: document.referrer, - browserName: navigator.appName, - userAgent: navigator.userAgent, - pathName: window.location.pathname, - onLine: navigator.onLine - }); - } + /** + * Trigger the change event for this form. + * @param {any} flags - The flags to set on this change event. + * @param {any} changed - The changed object which reflects the changes in the form. + * @param {boolean} modified - Whether or not the form has been modified. + * @param {any} changes - The changes that have occured in the form. + */ + onChange(flags, changed, modified, changes) { + flags = flags || {}; + let isChangeEventEmitted = false; + super.onChange(flags, true); + const value = _.clone(this.submission); + flags.changed = value.changed = changed; + flags.changes = changes; + + if (modified && this.pristine) { + this.pristine = false; + } - submitForm(options = {}) { - this.clearServerErrors(); + this.checkData(value.data, flags); + const shouldValidate = + !flags.noValidate || + flags.fromIFrame || + (flags.fromSubmission && this.rootPristine && this.pristine && flags.changed); + const errors = shouldValidate + ? this.validate(value.data, { ...flags, process: "change" }) + : []; + value.isValid = errors.length === 0; + + this.loading = false; + if (this.submitted) { + // show server errors while they are not cleaned/fixed + const nonComponentServerErrors = _.filter( + this.serverErrors || [], + (err) => !err.component && !err.path + ); + this.showErrors(nonComponentServerErrors.length ? nonComponentServerErrors : errors); + } - return new Promise((resolve, reject) => { - // Read-only forms should never submit. - if (this.options.readOnly) { - return resolve({ - submission: this.submission, - saved: false - }); - } + // See if we need to save the draft of the form. + if (modified && this.options.saveDraft) { + this.triggerSaveDraft(); + } - const submission = fastCloneDeep(this.submission || {}); + if (!flags || !flags.noEmit) { + this.emit("change", value, flags, modified); + isChangeEventEmitted = true; + } - this.setMetadata(submission); + // The form is initialized after the first change event occurs. + if (isChangeEventEmitted && !this.initialized) { + this.emit("initialized"); + this.initialized = true; + } + } - submission.state = options.state || submission.state || 'submitted'; + /** + * Send a delete request to the server. + * @returns {Promise} - The promise that is triggered when the delete is complete. + */ + deleteSubmission() { + return this.formio.deleteSubmission().then(() => { + this.emit("submissionDeleted", this.submission); + this.resetValue(); + }); + } - const isDraft = (submission.state === 'draft'); - this.hook('beforeSubmit', { ...submission, component: options.component }, (err , data) => { - if (err) { - return reject(err); + /** + * Cancels the submission. + * @param {boolean} noconfirm - Whether or not to confirm the cancellation. + * @alias reset + * @returns {boolean} - TRUE means the submission was cancelled, FALSE otherwise. + */ + cancel(noconfirm) { + const shouldReset = this.hook("beforeCancel", true); + if (shouldReset && (noconfirm || confirm(this.t("confirmCancel")))) { + this.resetValue(); + return true; + } else { + this.emit("cancelSubmit"); + return false; } + } + + setMetadata(submission) { + // Add in metadata about client submitting the form + submission.metadata = submission.metadata || {}; + _.defaults(submission.metadata, { + timezone: _.get(this, "_submission.metadata.timezone", currentTimezone()), + offset: parseInt(_.get(this, "_submission.metadata.offset", moment().utcOffset()), 10), + origin: document.location.origin, + referrer: document.referrer, + browserName: navigator.appName, + userAgent: navigator.userAgent, + pathName: window.location.pathname, + onLine: navigator.onLine, + }); + } - submission._vnote = data && data._vnote ? data._vnote : ''; + submitForm(options = {}) { + this.clearServerErrors(); - try { - if (!isDraft && !options.noValidate) { - if (!submission.data) { - return reject('Invalid Submission'); + return new Promise((resolve, reject) => { + // Read-only forms should never submit. + if (this.options.readOnly) { + return resolve({ + submission: this.submission, + saved: false, + }); } - const errors = this.validate(submission.data, { - dirty: true, - silentCheck: false, - process: 'submit' - }); - if (errors.length || options.beforeSubmitResults?.some((result) => result.status === 'rejected')) { - return reject(errors); - } - } - } - catch (err) { - console.error(err); - } - this.everyComponent((comp) => { - if (submission._vnote && comp.type === 'form' && comp.component.reference) { - _.get(submission.data, comp.path, {})._vnote = submission._vnote; - } - const { persistent } = comp.component; - if (persistent === 'client-only') { - _.unset(submission.data, comp.path); - } + const submission = fastCloneDeep(this.submission || {}); + + this.setMetadata(submission); + + submission.state = options.state || submission.state || "submitted"; + + const isDraft = submission.state === "draft"; + this.hook( + "beforeSubmit", + { ...submission, component: options.component }, + (err, data) => { + if (err) { + return reject(err); + } + + submission._vnote = data && data._vnote ? data._vnote : ""; + + try { + if (!isDraft && !options.noValidate) { + if (!submission.data) { + return reject("Invalid Submission"); + } + const errors = this.validate(submission.data, { + dirty: true, + silentCheck: false, + process: "submit", + }); + if ( + errors.length || + options.beforeSubmitResults?.some( + (result) => result.status === "rejected" + ) + ) { + return reject(errors); + } + } + } catch (err) { + console.error(err); + } + + this.everyComponent((comp) => { + if (submission._vnote && comp.type === "form" && comp.component.reference) { + _.get(submission.data, comp.path, {})._vnote = submission._vnote; + } + const { persistent } = comp.component; + if (persistent === "client-only") { + _.unset(submission.data, comp.path); + } + }); + + this.hook( + "customValidation", + { ...submission, component: options.component }, + (err) => { + if (err) { + // If string is returned, cast to object. + if (typeof err === "string") { + err = { + message: err, + }; + } + + // Ensure err is an array. + err = Array.isArray(err) ? err : [err]; + return reject(err); + } + + this.loading = true; + + // Use the form action to submit the form if available. + if (this._form && this._form.action) { + const method = + submission.data._id && + this._form.action.includes(submission.data._id) + ? "PUT" + : "POST"; + return Formio.makeStaticRequest( + this._form.action, + method, + submission, + this.formio ? this.formio.options : {} + ) + .then((result) => + resolve({ + submission: result, + saved: true, + }) + ) + .catch((error) => { + this.setServerErrors(error); + + return reject(error); + }); + } + + const submitFormio = this.formio; + if (this.nosubmit || !submitFormio) { + return resolve({ + submission, + saved: false, + }); + } + // If this is an actionUrl, then make sure to save the action and not the submission. + const submitMethod = submitFormio.actionUrl + ? "saveAction" + : "saveSubmission"; + submitFormio[submitMethod](submission) + .then((result) => + resolve({ + submission: result, + saved: true, + }) + ) + .catch((error) => { + this.setServerErrors(error); + + return reject(error); + }); + } + ); + } + ); }); + } - this.hook('customValidation', { ...submission, component: options.component }, (err) => { - if (err) { - // If string is returned, cast to object. - if (typeof err === 'string') { - err = { - message: err - }; - } + setServerErrors(error) { + if (error.details) { + this.serverErrors = error.details + .filter((err) => (err.level ? err.level === "error" : err)) + .map((err) => { + err.fromServer = true; + return err; + }); + } else if (typeof error === "string") { + this.serverErrors = [{ fromServer: true, level: "error", message: error }]; + } + } - // Ensure err is an array. - err = Array.isArray(err) ? err : [err]; - return reject(err); - } - - this.loading = true; - - // Use the form action to submit the form if available. - if (this._form && this._form.action) { - const method = (submission.data._id && this._form.action.includes(submission.data._id)) ? 'PUT' : 'POST'; - return Formio.makeStaticRequest(this._form.action, method, submission, this.formio ? this.formio.options : {}) - .then((result) => resolve({ - submission: result, - saved: true, - })) - .catch((error) => { - this.setServerErrors(error); - - return reject(error); - }); - } - - const submitFormio = this.formio; - if (this.nosubmit || !submitFormio) { - return resolve({ - submission, - saved: false, + executeSubmit(options) { + this.submitted = true; + this.submitting = true; + return this.submitForm(options) + .then(({ submission, saved }) => this.onSubmit(submission, saved)) + .then((results) => { + this.submissionInProcess = false; + return results; + }) + .catch((err) => { + this.submissionInProcess = false; + return Promise.reject(this.onSubmissionError(err)); }); - } - // If this is an actionUrl, then make sure to save the action and not the submission. - const submitMethod = submitFormio.actionUrl ? 'saveAction' : 'saveSubmission'; - submitFormio[submitMethod](submission) - .then((result) => resolve({ - submission: result, - saved: true, - })) - .catch((error) => { - this.setServerErrors(error); - - return reject(error); - }); - }); - }); - }); - } - - setServerErrors(error) { - if (error.details) { - this.serverErrors = error.details.filter((err) => err.level ? err.level === 'error' : err).map((err) => { - err.fromServer = true; - return err; - }); - } - else if (typeof error === 'string') { - this.serverErrors = [{ fromServer: true, level: 'error', message: error }]; - } - } - - executeSubmit(options) { - this.submitted = true; - this.submitting = true; - return this.submitForm(options) - .then(({ submission, saved }) => this.onSubmit(submission, saved)) - .then((results) => { - this.submissionInProcess = false; - return results; - }) - .catch((err) => { - this.submissionInProcess = false; - return Promise.reject(this.onSubmissionError(err)); - }); - } - - clearServerErrors() { - this.serverErrors?.forEach((error) => { - if (error.path) { - const pathArray = getArrayFromComponentPath(error.path); - const component = this.getComponent(pathArray, _.identity, error.formattedKeyOrPath); - - if (component) { - component.serverErrors = []; - } - } - }); - this.serverErrors = []; - } - - /** - * Submits the form. - * - * @example - * import Webform from '@formio/js/Webform'; - * let form = new Webform(document.getElementById('formio')); - * form.src = 'https://examples.form.io/example'; - * form.submission = {data: { - * firstName: 'Joe', - * lastName: 'Smith', - * email: 'joe@example.com' - * }}; - * form.submit().then((submission) => { - * console.log(submission); - * }); - * - * @param {boolean} before - If this submission occured from the before handlers. - * - * @returns {Promise} - A promise when the form is done submitting. - */ - submit(before, options = {}) { - this.submissionInProcess = true; - if (!before) { - return this.beforeSubmit(options).then(() => this.executeSubmit(options)); - } - else { - return this.executeSubmit(options); - } - } - - submitUrl(URL, headers) { - if (!URL) { - return console.warn('Missing URL argument'); - } - - const submission = this.submission || {}; - const API_URL = URL; - const settings = { - method: 'POST', - headers: {} - }; + } - if (headers && headers.length > 0) { - headers.map((e) => { - if (e.header !== '' && e.value !== '') { - settings.headers[e.header] = this.interpolate(e.value, submission); - } - }); - } - if (API_URL && settings) { - Formio.makeStaticRequest(API_URL,settings.method,submission, { headers: settings.headers }).then(() => { - this.emit('requestDone'); - this.setAlert('success', '

Success

'); - }).catch((e) => { - const message = `${e.statusText ? e.statusText : ''} ${e.status ? e.status : e}`; - this.emit('error', message); - console.error(message); - this.setAlert('danger', `

${message}

`); - return Promise.reject(this.onSubmissionError(e)); + clearServerErrors() { + this.serverErrors?.forEach((error) => { + if (error.path) { + const pathArray = getArrayFromComponentPath(error.path); + const component = this.getComponent( + pathArray, + _.identity, + error.formattedKeyOrPath + ); + + if (component) { + component.serverErrors = []; + } + } }); + this.serverErrors = []; } - else { - this.emit('error', 'You should add a URL to this button.'); - this.setAlert('warning', 'You should add a URL to this button.'); - return console.warn('You should add a URL to this button.'); + + /** + * Submits the form. + * @example + * import Webform from '@formio/js/Webform'; + * let form = new Webform(document.getElementById('formio')); + * form.src = 'https://examples.form.io/example'; + * form.submission = {data: { + * firstName: 'Joe', + * lastName: 'Smith', + * email: 'joe@example.com' + * }}; + * form.submit().then((submission) => { + * console.log(submission); + * }); + * @param {boolean} before - If this submission occured from the before handlers. + * @param {any} options - The options to use when submitting this form. + * @returns {Promise} - A promise when the form is done submitting. + */ + submit(before, options = {}) { + this.submissionInProcess = true; + if (!before) { + return this.beforeSubmit(options).then(() => this.executeSubmit(options)); + } else { + return this.executeSubmit(options); + } } - } - triggerRecaptcha() { - if (!this || !this.components) { - return; + submitUrl(URL, headers) { + if (!URL) { + return console.warn("Missing URL argument"); + } + + const submission = this.submission || {}; + const API_URL = URL; + const settings = { + method: "POST", + headers: {}, + }; + + if (headers && headers.length > 0) { + headers.map((e) => { + if (e.header !== "" && e.value !== "") { + settings.headers[e.header] = this.interpolate(e.value, submission); + } + }); + } + if (API_URL && settings) { + Formio.makeStaticRequest(API_URL, settings.method, submission, { + headers: settings.headers, + }) + .then(() => { + this.emit("requestDone"); + this.setAlert("success", "

Success

"); + }) + .catch((e) => { + const message = `${e.statusText ? e.statusText : ""} ${e.status ? e.status : e}`; + this.emit("error", message); + console.error(message); + this.setAlert("danger", `

${message}

`); + return Promise.reject(this.onSubmissionError(e)); + }); + } else { + this.emit("error", "You should add a URL to this button."); + this.setAlert("warning", "You should add a URL to this button."); + return console.warn("You should add a URL to this button."); + } } - const recaptchaComponent = searchComponents(this.components, { - 'component.type': 'recaptcha', - 'component.eventType': 'formLoad' - }); - if (recaptchaComponent.length > 0) { - recaptchaComponent[0].verify(`${this.form.name ? this.form.name : 'form'}Load`); + + triggerRecaptcha() { + if (!this || !this.components) { + return; + } + const recaptchaComponent = searchComponents(this.components, { + "component.type": "recaptcha", + "component.eventType": "formLoad", + }); + if (recaptchaComponent.length > 0) { + recaptchaComponent[0].verify(`${this.form.name ? this.form.name : "form"}Load`); + } } - } - set nosubmit(value) { - this._nosubmit = !!value; - this.emit('nosubmit', this._nosubmit); - } + set nosubmit(value) { + this._nosubmit = !!value; + this.emit("nosubmit", this._nosubmit); + } - get nosubmit() { - return this._nosubmit || false; - } + get nosubmit() { + return this._nosubmit || false; + } - get conditions() { - return this.schema.settings?.conditions ?? []; - } + get conditions() { + return this.schema.settings?.conditions ?? []; + } - get variables() { - return this.schema.settings?.variables ?? []; - } + get variables() { + return this.schema.settings?.variables ?? []; + } } Webform.setBaseUrl = Formio.setBaseUrl; diff --git a/src/WebformBuilder.js b/src/WebformBuilder.js index ea86442243..b4104b8883 100644 --- a/src/WebformBuilder.js +++ b/src/WebformBuilder.js @@ -439,7 +439,6 @@ export default class WebformBuilder extends Component { /** * Called when everything is ready. - * * @returns {Promise} - Wait for webform to be ready. */ get ready() { @@ -495,7 +494,8 @@ export default class WebformBuilder extends Component { /** * When a component sets its api key, we need to check if it is unique within its namespace. Find the namespace root * so we can calculate this correctly. - * @param component + * @param {import('@formio/core').Component} component - The component to find the namespace root for. + * @returns {import('@formio/core').Component[]} - The components root for this namespace. */ findNamespaceRoot(component) { const path = getArrayFromComponentPath(component.path); @@ -1300,10 +1300,11 @@ export default class WebformBuilder extends Component { /** * Called when a new component is saved. - * - * @param parent - * @param component - * @return {boolean} + * @param {Component} component - The component instance to save. + * @param {Component} parent - The parent component. + * @param {boolean} isNew - If this is a new component. + * @param {Component} original - The original component. + * @returns {boolean} - If the component was saved. */ saveComponent(component, parent, isNew, original) { this.editForm.detach(); @@ -1776,8 +1777,8 @@ export default class WebformBuilder extends Component { /** * Creates copy of component schema and stores it under sessionStorage. - * @param {Component} component - * @return {*} + * @param {Component} component - The component to copy. + * @returns {void} */ copyComponent(component) { if (!window.sessionStorage) { @@ -1789,8 +1790,8 @@ export default class WebformBuilder extends Component { /** * Paste copied component after the current component. - * @param {Component} component - * @return {*} + * @param {Component} component - The component to paste after. + * @returns {void} */ pasteComponent(component) { if (!window.sessionStorage) { diff --git a/src/Wizard.js b/src/Wizard.js index 7b8de1243c..7ba379eddc 100644 --- a/src/Wizard.js +++ b/src/Wizard.js @@ -8,30 +8,26 @@ import { firstNonNil, uniqueKey, eachComponent, - unescapeHTML } from './utils/utils'; export default class Wizard extends Webform { /** - * Constructor for wizard based forms - * @param element Dom element to place this wizard. - * @param {Object} options Options object, supported options are: - * - breadcrumbSettings.clickable: true (default) determines if the breadcrumb bar is clickable or not - * - buttonSettings.show*(Previous, Next, Cancel): true (default) determines if the button is shown or not - * - allowPrevious: false (default) determines if the breadcrumb bar is clickable or not for visited tabs + * Constructor for wizard-based forms. + * @param {HTMLElement | object | import('Form').FormOptions} [elementOrOptions] - The DOM element to render this form within or the options to create this form instance. + * @param {import('Form').FormOptions} [_options] - The options to create a new form instance. + * - breadcrumbSettings.clickable: true (default) - determines if the breadcrumb bar is clickable. + * - buttonSettings.show*(Previous, Next, Cancel): true (default) - determines if the button is shown. + * - allowPrevious: false (default) - determines if the breadcrumb bar is clickable for visited tabs. */ - constructor() { + constructor(elementOrOptions, _options) { let element, options; - if (arguments[0] instanceof HTMLElement || arguments[1]) { - element = arguments[0]; - options = arguments[1] || {}; + if (elementOrOptions instanceof HTMLElement || options) { + element = elementOrOptions; + options = _options; + } else { + options = elementOrOptions; } - else { - options = arguments[0] || {}; - } - options.display = 'wizard'; - super(element, options); this.pages = []; this.prefixComps = []; @@ -116,7 +112,7 @@ export default class Wizard extends Webform { }); if (!this.isSecondInit) { - this.isClickableDefined = this.options?.breadcrumbSettings?.hasOwnProperty('clickable'); + this.isClickableDefined = Object.prototype.hasOwnProperty.call(this.options?.breadcrumbSettings, 'clickable'); this.isSecondInit = true; } @@ -288,6 +284,13 @@ export default class Wizard extends Webform { } } + /** + * Attaches the wizard to the provided DOM element, initializes component references, sets up navigation, + * and emits a render event. It will initialize the wizard's index if necessary, + * attach event hooks, and make sure that the current page is rendered and displayed correctly. + * @param {HTMLElement} element - The DOM element to which the wizard will be attached. + * @returns {Promise} A promise that resolves when all components have been successfully attached. + */ attach(element) { this.setElement(element); this.loadRefs(element, { @@ -357,6 +360,10 @@ export default class Wizard extends Webform { return _.get(currentPage.component, 'allowPrevious', this.options.allowPrevious); } + /** + * Handles navigate on 'Enter' key event in a wizard form. + * @param {KeyboardEvent} event - The keyboard event object that triggered the handler. + */ handleNaviageteOnEnter(event) { if (event.keyCode === 13) { const clickEvent = new CustomEvent('click'); @@ -367,6 +374,10 @@ export default class Wizard extends Webform { } } + /** + * Handles save on 'Enter' key event in a wizard form. + * @param {KeyboardEvent} event - The keyboard event object that triggered the handler. + */ handleSaveOnEnter(event) { if (event.keyCode === 13) { const clickEvent = new CustomEvent('click'); @@ -405,6 +416,12 @@ export default class Wizard extends Webform { }); } + + /** + * Emits an event indicating that a wizard page has been selected. + * @param {number} index - Index of the selected wizard page in the `pages` array. + * @fires emit - Emits the 'wizardPageSelected' event with the page object and index. + */ emitWizardPageSelected(index) { this.emit('wizardPageSelected', this.pages[index], index); } @@ -865,7 +882,10 @@ export default class Wizard extends Webform { this.options.show = this.options.show || {}; this.options.show[item.key] = true; } - else if (this.wizard.hasOwnProperty('full') && !_.isEqual(this.originalOptions.show, this.options.show)) { + else if ( + Object.prototype.hasOwnProperty.call(this.wizard, 'full') + && !_.isEqual(this.originalOptions.show, this.options.show) + ) { this.options.show = { ...(this.originalOptions.show || {}) }; } } diff --git a/src/addons/PasswordStrength/PasswordStrengthAddon.js b/src/addons/PasswordStrength/PasswordStrengthAddon.js index 977652e7bb..de9a97c309 100644 --- a/src/addons/PasswordStrength/PasswordStrengthAddon.js +++ b/src/addons/PasswordStrength/PasswordStrengthAddon.js @@ -226,7 +226,7 @@ export default class PasswordStrengthAddon extends FormioAddon { /** * Determines is a password is secure enough to submit - * @return {boolean} + * @returns {boolean} - returns TRUE if password is valid, FALSE if it is not. */ isValid() { const isValidCheck = this.settings.isValid; @@ -245,8 +245,9 @@ export default class PasswordStrengthAddon extends FormioAddon { * Handles the result of check and constructs a new error object or returns an amount of points to add to the current entropy * @param {boolean|number} valid - Determines if the validation was failed or an amount of points if it was passed * @param {*} validation - Validation configuration - * @param {string} value - Value which was validated * @param {string} message - Message which should be shown if validation was not passed + * @param {any[]} errors - The errors array (will be mutated) + * @returns {number} - Returns an amount of points to add to the current entropy */ handleRuleCheckResult(valid, validation, message, errors) { if (valid !== true) { @@ -292,7 +293,8 @@ export default class PasswordStrengthAddon extends FormioAddon { /** * Performs checks to validate password security - * @param {string} value - Suggested password + * @param {string} value - The password value to be checked. + * @returns {boolean} - Returns TRUE if password is strong enough, FALSE if it is not. */ checkValidity(value) { const passwordLength = value.length; @@ -408,6 +410,7 @@ export default class PasswordStrengthAddon extends FormioAddon { /** * Finds the level which one the passed entropy suits * @param {number} entropy - Points of password's security + * @returns {object} - Returns the level object */ getLevel(entropy = this.entropy) { const lowestLevel = this.levels[0]; diff --git a/src/components/Components.js b/src/components/Components.js index 0819c682ff..2b732282d3 100644 --- a/src/components/Components.js +++ b/src/components/Components.js @@ -58,9 +58,8 @@ export default class Components { /** * Return a path of component's value. - * - * @param {Object} component - The component instance. - * @return {string} - The component's value path. + * @param {Component} component - The component instance. + * @returns {string} - The component's value path. */ static getComponentPath(component) { let path = ''; @@ -79,6 +78,7 @@ export default class Components { path += component.component.key; return _.trim(path, '.'); } + return path; } static create(component, options, data) { diff --git a/src/components/_classes/component/Component.form.js b/src/components/_classes/component/Component.form.js index 91809511ef..29638d3b63 100644 --- a/src/components/_classes/component/Component.form.js +++ b/src/components/_classes/component/Component.form.js @@ -9,6 +9,11 @@ import ComponentEditValidation from './editForm/Component.edit.validation'; import ComponentEditLayout from './editForm/Component.edit.layout'; import EditFormUtils from './editForm/utils'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { const components = _.cloneDeep([ { diff --git a/src/components/_classes/component/Component.js b/src/components/_classes/component/Component.js index 9daa721c25..3c3606f3c2 100644 --- a/src/components/_classes/component/Component.js +++ b/src/components/_classes/component/Component.js @@ -194,9 +194,7 @@ export default class Component extends Element { } /** * Return the simple condition settings as part of the component. - * - * @return {Object} - * + * @returns {object} - The simple conditional settings. */ static get conditionOperatorsSettings() { return { @@ -213,10 +211,8 @@ export default class Component extends Element { } /** * Return the array of possible types of component value absed on its schema. - * * @param schema - * @return {Array} - * + * @returns {Array} */ static savedValueTypes(schema) { @@ -227,7 +223,6 @@ export default class Component extends Element { /** * Provides a table view for this component. Override if you wish to do something different than using getView * method of your instance. - * * @param value * @param options */ @@ -237,10 +232,9 @@ export default class Component extends Element { /** * Initialize a new Component. - * - * @param {Object} component - The component JSON you wish to initialize. - * @param {Object} options - The options for this component. - * @param {Object} data - The global data submission object this component will belong. + * @param {object} component - The component JSON you wish to initialize. + * @param {object} options - The options for this component. + * @param {object} data - The global data submission object this component will belong. */ /* eslint-disable max-statements */ constructor(component, options, data) { @@ -278,7 +272,6 @@ export default class Component extends Element { /** * The data path to this specific component instance. - * * @type {string} */ this.path = component?.key || ''; @@ -338,21 +331,18 @@ export default class Component extends Element { /** * Points to a flat map of child components (if applicable). - * - * @type {Object} + * @type {object} */ this.childComponentsMap = {}; /** * Determines if this component is disabled, or not. - * * @type {boolean} */ this._disabled = boolValue(this.component.disabled) ? this.component.disabled : false; /** * Points to the root component, usually the FormComponent. - * * @type {Component} */ this.root = this.options.root || this; @@ -360,14 +350,12 @@ export default class Component extends Element { /** * If this input has been input and provided value. - * * @type {boolean} */ this.pristine = true; /** * Points to the parent component. - * * @type {Component} */ this.parent = this.options.parent; @@ -393,7 +381,7 @@ export default class Component extends Element { /** * Used to trigger a new change in this component. - * @type {function} - Call to trigger a change in this component. + * @type {Function} - Call to trigger a change in this component. */ let changes = []; let lastChanged = null; @@ -435,7 +423,6 @@ export default class Component extends Element { /** * Used to trigger a redraw event within this component. - * * @type {Function} */ this.triggerRedraw = _.debounce(this.redraw.bind(this), 100); @@ -674,8 +661,8 @@ export default class Component extends Element { } /** - * - * @param value {boolean} + * Sets the component visibility. + * @param {boolean} value - Whether the component should be visible or not. */ set visible(value) { if (this._visible !== value) { @@ -694,8 +681,8 @@ export default class Component extends Element { } /** - * - * @returns {boolean} + * Returns the component visibility + * @returns {boolean} - Whether the component is visible or not. */ get visible() { // Show only if visibility changes or if we are in builder mode or if hidden fields should be shown. @@ -802,9 +789,10 @@ export default class Component extends Element { /** * Returns only the schema that is different from the default. - * - * @param schema - * @param defaultSchema + * @param {object} schema - The "full" json schema for the component. + * @param {object} defaultSchema - The "default" json schema for the component. + * @param {boolean} recursion - If we are currently in a recursive loop. + * @returns {object} - The minified json schema for this component. */ getModifiedSchema(schema, defaultSchema, recursion) { const modified = {}; @@ -841,6 +829,7 @@ export default class Component extends Element { /** * Returns the JSON schema for this component. + * @returns {object} - The JSON schema for this component. */ get schema() { return fastCloneDeep(this.getModifiedSchema(_.omit(this.component, 'id'), this.defaultSchema)); @@ -848,6 +837,7 @@ export default class Component extends Element { /** * Returns true if component is inside DataGrid + * @returns {boolean} - True if component is inside DataGrid */ get isInDataGrid() { return this.inDataGrid; @@ -855,9 +845,10 @@ export default class Component extends Element { /** * Translate a text using the i18n system. - * * @param {string} text - The i18n identifier. - * @param {Object} params - The i18n parameters to use for translation. + * @param {object} params - The i18n parameters to use for translation. + * @param {...any} args - Additional arguments to pass to the translation library. + * @returns {string} - The translated text. */ t(text, params = {}, ...args) { if (!text) { @@ -1015,9 +1006,10 @@ export default class Component extends Element { /** * Sanitize an html string. - * - * @param string - * @returns {*} + * @param {string} dirty - The dirty html string to sanitize. + * @param {boolean} forceSanitize - If we should force the sanitize to occur. + * @param {object} options - The options for the sanitize. + * @returns {*} - The sanitized html string. */ sanitize(dirty, forceSanitize, options) { if (!this.shouldSanitizeValue && !forceSanitize) { @@ -1032,12 +1024,9 @@ export default class Component extends Element { /** * Render a template string into html. - * - * @param template - * @param data - * @param actions - * - * @return {HTMLElement|String} - The created element or an empty string if template is not specified. + * @param {string} template - The template to render. + * @param {object} data - The data to provide to the template. + * @returns {HTMLElement | string} - The created element or an empty string if template is not specified. */ renderString(template, data) { if (!template) { @@ -1047,10 +1036,19 @@ export default class Component extends Element { return this.interpolate(template, data); } + /** + * Allows for modification of the component value prior to submission. + * @param {*} input - The input to be modified. + * @returns {*} - The modified input mapping for the extended component. + */ performInputMapping(input) { return input; } + /** + * Returns the component "widget" if one is available. + * @returns {Widget|null} - The widget instance. null if not available. + */ get widget() { const settings = this.component.widget; @@ -1062,6 +1060,10 @@ export default class Component extends Element { return widget; } + /** + * Returns the native supported browser language. + * @returns {string|null} - The native browser language that is supported. + */ getBrowserLanguage() { const nav = window.navigator; const browserLanguagePropertyKeys = ['language', 'browserLanguage', 'systemLanguage', 'userLanguage']; @@ -1089,24 +1091,24 @@ export default class Component extends Element { } /** - * Called before a next and previous page is triggered allowing the components - * to perform special functions. - * - * @return {*} + * Called before a next and previous page is triggered allowing the components to perform special functions. + * @returns {Promise} - A promise to resolve when the component is no longer blocking the next/previous page navigation. */ beforePage() { return Promise.resolve(true); } + /** + * Called before the next page is triggered allowing the components to hook into the page navigation and perform tasks. + * @returns {Promise} - A promise to resolve when the component is no longer blocking the next page navigation. + */ beforeNext() { return this.beforePage(true); } /** - * Called before a submission is triggered allowing the components - * to perform special async functions. - * - * @return {*} + * Called before a submission is triggered allowing the components to perform special async functions. + * @returns {Promise} - A promise to resolve when the component is no longer blocking the submission. */ beforeSubmit() { return Promise.resolve(true); @@ -1114,18 +1116,26 @@ export default class Component extends Element { /** * Return the submission timezone. - * - * @return {*} + * @returns {string} - The submission timezone. */ get submissionTimezone() { this.options.submissionTimezone = this.options.submissionTimezone || _.get(this.root, 'options.submissionTimezone'); return this.options.submissionTimezone; } + /** + * Return the current timezone. + * @returns {string} - The current timezone. + */ get timezone() { return this.getTimezone(this.component); } + /** + * Return the current timezone. + * @param {object} settings - Settings to control how the timezone should be returned. + * @returns {string} - The current timezone. + */ getTimezone(settings) { if (settings.timezone) { return settings.timezone; @@ -1172,10 +1182,18 @@ export default class Component extends Element { } } - setOpenModalElement(template) { + /** + * Opens the modal element. + * @param {string} template - The template to use for the modal dialog. + */ + setOpenModalElement(template = null) { this.componentModal.setOpenModalElement(template || this.getModalPreviewTemplate()); } + /** + * Returns the modal preview template. + * @returns {string} - The modal preview template. + */ getModalPreviewTemplate() { const dataValue = this.component.type === 'password' ? this.dataValue.replace(/./g, '•') : this.dataValue; let modalLabel; @@ -1191,6 +1209,11 @@ export default class Component extends Element { }); } + /** + * Performs a complete build of a component, which empties, renders, sets the content in the DOM, and then finally attaches events. + * @param {HTMLElement} element - The element to attach this component to. + * @returns {Promise} - A promise that resolves when the component has been built. + */ build(element) { element = element || this.element; this.empty(element); @@ -1202,6 +1225,12 @@ export default class Component extends Element { return true; } + /** + * Renders a component as an HTML string. + * @param {string} children - The contents of all the children HTML as a string. + * @param {boolean} topLevel - If this is the topmost component that is being rendered. + * @returns {string} - The rendered HTML string of a component. + */ render(children = `Unknown component: ${this.component.type}`, topLevel = false) { const isVisible = this.visible; this.rendered = true; @@ -1227,6 +1256,11 @@ export default class Component extends Element { } } + /** + * Attaches all the tooltips provided the refs object. + * @param {object} toolTipsRefs - The refs for the tooltips within your template. + * @returns {void} + */ attachTooltips(toolTipsRefs) { toolTipsRefs?.forEach((tooltip, index) => { if (tooltip) { @@ -1247,10 +1281,22 @@ export default class Component extends Element { }); } + /** + * Create a new component modal for this component. + * @param {HTMLElement} element - The element to attach the modal to. + * @param {boolean} modalShouldBeOpened - TRUE if the modal should open immediately. + * @param {any} currentValue - The current value of the component. + * @returns {ComponentModal} - The created component modal. + */ createComponentModal(element, modalShouldBeOpened, currentValue) { return new ComponentModal(this, element, modalShouldBeOpened, currentValue, this._referenceAttributeName); } + /** + * Attaches all event listensers for this component to the DOM elements that were rendered. + * @param {HTMLElement} element - The element to attach the listeners to. + * @returns {Promise} - Resolves when the component is done attaching to the DOM. + */ attach(element) { if (!this.builderMode && !this.previewMode && this.component.modalEdit) { const modalShouldBeOpened = this.componentModal ? this.componentModal.isOpened : false; @@ -1298,6 +1344,9 @@ export default class Component extends Element { return Promise.resolve(); } + /** + * Restors the "focus" on a component after a redraw event has occured. + */ restoreFocus() { const isFocused = this.root?.focusedComponent?.path === this.path; if (isFocused) { @@ -1307,6 +1356,12 @@ export default class Component extends Element { } } + /** + * Adds a keyboard shortcut to this component. + * @param {HTMLElement} element - The element to attach the keyboard shortcut to. + * @param {string} shortcut - The keyboard shortcut to add. + * @returns {void} + */ addShortcut(element, shortcut) { // Avoid infinite recursion. if (!element || !this.root || (this.root === this)) { @@ -1320,6 +1375,12 @@ export default class Component extends Element { this.root.addShortcut(element, shortcut); } + /** + * Removes a keyboard shortcut from this component. + * @param {HTMLElement} element - The element to remove the keyboard shortcut from. + * @param {string} shortcut - The keyboard shortcut to remove. + * @returns {void} + */ removeShortcut(element, shortcut) { // Avoid infinite recursion. if (!element || (this.root === this)) { @@ -1356,6 +1417,13 @@ export default class Component extends Element { } } + /** + * Determines if the component should be refreshed based on the path of another component that changed. + * @param {string} refreshData - The path of the data that needs to trigger a refresh. + * @param {boolean} changed - Flag that is true if the data has been changed. + * @param {any} flags - The flags for the checkData procedure. + * @returns {void} + */ checkRefresh(refreshData, changed, flags) { const changePath = _.get(changed, 'instance.path', false); // Don't let components change themselves. @@ -1375,6 +1443,12 @@ export default class Component extends Element { } } + /** + * Iterates over a list of changes, and determines if the component should be refreshed if it is configured to refresh on any of those components. + * @param {Array} changes - The list of components that have changed. + * @param {any} flags - The checkData flags. + * @returns {void} + */ checkRefreshOn(changes, flags = {}) { changes = changes || []; if (flags.noRefresh) { @@ -1397,8 +1471,8 @@ export default class Component extends Element { /** * Refreshes the component with a new value. - * - * @param value + * @param {any} value - The latest value of the component to check if it needs to be refreshed. + * @returns {void} */ refresh(value) { if (this.hasOwnProperty('refreshOnValue')) { @@ -1422,8 +1496,8 @@ export default class Component extends Element { * with the components data and returns true if they are in the same context. * * Different rows of the same EditGrid, for example, are in different contexts. - * - * @param component + * @param {any} component - The component to check if it is in the same context as this component. + * @returns {boolean} - TRUE if the component is in the same context as this component. */ inContext(component) { if (component.data === this.data) { @@ -1440,10 +1514,19 @@ export default class Component extends Element { return false; } + /** + * Determines if we are in "view" only mode. + * @returns {boolean} - TRUE if we are in "view" only mode. + */ get viewOnly() { return this.options.readOnly && this.options.viewAsHtml; } + /** + * Sets the HTMLElement for this component. + * @param {HTMLElement} element - The element that is attached to this component. + * @returns {void} + */ setElement(element) { if (this.element) { delete this.element.component; @@ -1452,6 +1535,10 @@ export default class Component extends Element { this.element = element; } + /** + * Creates an element to hold the "view only" version of this component. + * @returns {HTMLElement} - The element for this component. + */ createViewOnlyElement() { this.setElement(this.ce('dl', { id: this.id @@ -1465,15 +1552,19 @@ export default class Component extends Element { return this.element; } + /** + * The default value for the "view only" mode of a component if the value is not provided. + * @returns {string} - The default value for this component. + */ get defaultViewOnlyValue() { return '-'; } /** * Uses the widget to determine the output string. - * - * @param value - * @return {*} + * @param {any} value - The current value of the component. + * @param {any} options - The options for getValueAsString. + * @returns {any|Array} - The value as a string. */ getWidgetValueAsString(value, options) { const noInputWidget = !this.refs.input || !this.refs.input[0] || !this.refs.input[0].widget; @@ -1500,6 +1591,12 @@ export default class Component extends Element { return widget.getValueAsString(value, options); } + /** + * Returns the value of the component as a string. + * @param {any} value - The value for this component. + * @param {any} options - The options for this component. + * @returns {string} - The string representation of the value of this component. + */ getValueAsString(value, options) { if (!value) { return ''; @@ -1518,6 +1615,12 @@ export default class Component extends Element { return this.sanitize(stringValue); } + /** + * Returns the string representation "view" of the component value. + * @param {any} value - The value of the component. + * @param {any} options - The options for this component. + * @returns {string} - The string representation of the value of this component. + */ getView(value, options) { if (this.component.protected) { return '--- PROTECTED ---'; @@ -1525,15 +1628,21 @@ export default class Component extends Element { return this.getValueAsString(value, options); } + /** + * Updates the items list for this component. Useful for Select and other List component types. + * @param {...any} args - The arguments to pass to the onChange event. + * @returns {void} + */ updateItems(...args) { this.restoreValue(); this.onChange(...args); } /** - * @param {*} data - * @param {boolean} [forceUseValue=false] - if true, return 'value' property of the data - * @return {*} + * Returns the value for a specific item in a List type component. + * @param {any} data - The data for this component. + * @param {boolean} [forceUseValue] - if true, return 'value' property of the data + * @returns {any} - The value of the item. */ itemValue(data, forceUseValue = false) { if (_.isObject(data) && !_.isArray(data)) { @@ -1549,6 +1658,11 @@ export default class Component extends Element { return data; } + /** + * Returns the item value for html mode. + * @param {any} value - The value for this component. + * @returns {any} - The value of the item for html mode. + */ itemValueForHTMLMode(value) { if (Array.isArray(value)) { const values = value.map(item => Array.isArray(item) ? this.itemValueForHTMLMode(item) : this.itemValue(item)); @@ -1559,6 +1673,13 @@ export default class Component extends Element { return this.itemValue(value); } + /** + * Creates a modal to input the value of this component. + * @param {HTMLElement} element - The element to attach the modal to. + * @param {any} attr - A list of attributes to add to the modal. + * @param {boolean} confirm - If we should add a confirmation to the modal that keeps it from closing unless confirmed. + * @returns {HTMLElement} - The created modal element. + */ createModal(element, attr, confirm) { const dialog = this.ce('div', attr || {}); this.setContent(dialog, this.renderTemplate('dialog')); @@ -1602,6 +1723,10 @@ export default class Component extends Element { return dialog; } + /** + * Uses CSS classes to show or hide an element. + * @returns {boolean} - TRUE if the element has been css removed. + */ get optimizeRedraw() { if (this.options.optimizeRedraw && this.element && !this.visible) { this.addClass(this.element, 'formio-removed'); @@ -1641,7 +1766,7 @@ export default class Component extends Element { /** * Build the custom style from the layout values - * @return {string} - The custom style + * @returns {string} - The custom style */ get customStyle() { let customCSS = ''; @@ -1653,17 +1778,25 @@ export default class Component extends Element { return customCSS; } + /** + * Returns the component condition operator settings if available. + * @returns {object} - The component condition operator settings. + */ static get serverConditionSettings() { return Component.conditionOperatorsSettings; } + /** + * Returns if the application is on a mobile device. + * @returns {boolean} - TRUE if the application is on a mobile device. + */ get isMobile() { return isMobile(); } /** * Returns the outside wrapping element of this component. - * @returns {HTMLElement} + * @returns {HTMLElement} - The wrapping element of this component. */ getElement() { return this.element; @@ -1671,9 +1804,8 @@ export default class Component extends Element { /** * Create an evaluation context for all script executions and interpolations. - * - * @param additional - * @return {*} + * @param {any} additional - Additional context to provide. + * @returns {any} - The evaluation context. */ evalContext(additional) { return super.evalContext(Object.assign({ @@ -1696,21 +1828,32 @@ export default class Component extends Element { /** * Sets the pristine flag for this component. - * - * @param pristine {boolean} - TRUE to make pristine, FALSE not pristine. + * @param {boolean} pristine - TRUE to make pristine, FALSE not pristine. */ setPristine(pristine) { this.pristine = pristine; } + /** + * Returns if the component is pristine. + * @returns {boolean} - TRUE if the component is pristine. + */ get isPristine() { return this.pristine; } + /** + * Sets the dirty flag for this component. + * @param {boolean} dirty - TRUE to make dirty, FALSE not dirty. + */ setDirty(dirty) { this.dirty = dirty; } + /** + * Returns if the component is dirty. + * @returns {boolean} - TRUE if the component is dirty. + */ get isDirty() { return this.dirty; } @@ -1726,6 +1869,12 @@ export default class Component extends Element { this.triggerRootChange(); } + /** + * Returns the icon class for a given icon name. + * @param {string} name - The name of the icon you wish to fetch provided the icon class. This is the "font awesome" version of the name of the icon. + * @param {boolean} spinning - If the component should be spinning. + * @returns {string} - The icon class for the equivalent icon in the iconset we are using. + */ iconClass(name, spinning) { const iconset = this.options.iconset || Templates.current.defaultIconset || 'fa'; return Templates.current.hasOwnProperty('iconClass') @@ -1733,6 +1882,11 @@ export default class Component extends Element { : this.options.iconset === 'fa' ? Templates.defaultTemplates.iconClass(iconset, name, spinning) : name; } + /** + * Returns the size css class names for our current template. + * @param {string} size - The size class name for the default iconset. + * @returns {string} - The size class for our component. + */ size(size) { return Templates.current.hasOwnProperty('size') ? Templates.current.size(size) @@ -1747,17 +1901,25 @@ export default class Component extends Element { return this.t(this.component.label || this.component.placeholder || this.key, { _userInput: true }); } + /** + * Returns the visible errors for this component. + * @returns {Array} - The visible errors for this component. + */ get visibleErrors() { return this._visibleErrors; } + /** + * Returns all the errors for this component, visible or not. + * @returns {Array} - All the errors for this component. + */ get errors() { return this._errors; } /** * Returns the error label for this component. - * @return {*} + * @returns {string} - The error label for this component. */ get errorLabel() { return this.t(this.component.errorLabel @@ -1768,13 +1930,21 @@ export default class Component extends Element { /** * Get the error message provided a certain type of error. - * @param type - * @return {*} + * @param {string} type - The type of error to fetch the message for. + * @returns {string} - The error message configured for this component. */ errorMessage(type) { return (this.component.errors && this.component.errors[type]) ? this.component.errors[type] : type; } + /** + * Sets the content, innerHTML, of an element to the sanitized content. + * @param {HTMLElement} element - The element to set the innerHTML to. + * @param {string} content - The HTML string content that we wish to set. + * @param {boolean} forceSanitize - If we should force the content to be sanitized. + * @param {any} sanitizeOptions - The options for the sanitize function. + * @returns {boolean} - TRUE if the content was sanitized and set. + */ setContent(element, content, forceSanitize, sanitizeOptions) { if (element instanceof HTMLElement) { element.innerHTML = this.sanitize(content, forceSanitize, sanitizeOptions); @@ -1783,6 +1953,9 @@ export default class Component extends Element { return false; } + /** + * Restores the caret position in the input element after a refresh occurs. + */ restoreCaretPosition() { if (this.root?.currentSelection) { if (this.refs.input?.length) { @@ -1805,6 +1978,10 @@ export default class Component extends Element { } } + /** + * Redraw the component. + * @returns {Promise} - A promise that resolves when the component is done redrawing. + */ redraw() { // Don't bother if we have not built yet. if (!this.element || !this.element.parentNode || this.optimizeRedraw) { @@ -1821,6 +1998,10 @@ export default class Component extends Element { return this.attach(this.element); } + /** + * Rebuild and redraw a component. + * @returns {Promise} - A promise that resolves when the component is done rebuilding and redrawing. + */ rebuild() { this.destroy(); this.init(); @@ -1828,12 +2009,21 @@ export default class Component extends Element { return this.redraw(); } + /** + * Removes all event listeners attached to this component. + */ removeEventListeners() { super.removeEventListeners(); this.tooltips.forEach(tooltip => tooltip.destroy()); this.tooltips = []; } + /** + * Returns if the dom node has the classes provided. + * @param {HTMLElement} element - The element to check for the class. + * @param {string} className - The name of the class to check. + * @returns {boolean|void} - TRUE if the element has the class. + */ hasClass(element, className) { if (!element) { return; @@ -1842,6 +2032,12 @@ export default class Component extends Element { return super.hasClass(element, this.transform('class', className)); } + /** + * Adds a class to an HTML element. + * @param {HTMLElement} element - The dom element to add the class to. + * @param {string} className - The class name you wish to add. + * @returns {this|void} - The component instance. + */ addClass(element, className) { if (!element) { return; @@ -1850,6 +2046,12 @@ export default class Component extends Element { return super.addClass(element, this.transform('class', className)); } + /** + * Removes a class from an element. + * @param {HTMLElement} element - The element to remove the class from. + * @param {string} className - The class name to remove. + * @returns {this|void} - The component instance. + */ removeClass(element, className) { if (!element) { return; @@ -1860,8 +2062,7 @@ export default class Component extends Element { /** * Determines if this component has a condition defined. - * - * @return {null} + * @returns {boolean} - TRUE if the component has a condition defined. */ hasCondition() { if (this._hasCondition !== null) { @@ -1874,9 +2075,9 @@ export default class Component extends Element { /** * Check if this component is conditionally visible. - * - * @param data - * @return {boolean} + * @param {any} data - The data to check against. + * @param {any} row - The row data to check against. + * @returns {boolean} - TRUE if the component is conditionally visible. */ conditionallyVisible(data, row) { data = data || this.rootValue; @@ -1892,10 +2093,9 @@ export default class Component extends Element { * Checks the condition of this component. * * TODO: Switch row and data parameters to be consistent with other methods. - * - * @param row - The row contextual data. - * @param data - The global data object. - * @return {boolean} - True if the condition applies to this component. + * @param {any} row - The row contextual data. + * @param {any} data - The global data object. + * @returns {boolean} - True if the condition applies to this component. */ checkCondition(row, data) { return FormioUtils.checkCondition( @@ -1909,6 +2109,10 @@ export default class Component extends Element { /** * Check for conditionals and hide/show the element based on those conditions. + * @param {any} data - The data to check against. + * @param {any} flags - The flags passed to checkData function. + * @param {any} row - The row data to check against. + * @returns {boolean} - TRUE if the component is visible. */ checkComponentConditions(data, flags, row) { data = data || this.rootValue; @@ -1931,8 +2135,10 @@ export default class Component extends Element { /** * Checks conditions for this component and any sub components. - * @param args - * @return {boolean} + * @param {any} data - The data to check against. + * @param {any} flags - The flags passed to checkData function. + * @param {any} row - The row data to check against. + * @returns {boolean} - TRUE if the component is visible. */ checkConditions(data, flags, row) { data = data || this.rootValue; @@ -1941,18 +2147,21 @@ export default class Component extends Element { return this.checkComponentConditions(data, flags, row); } + /** + * Returns the component logic if applicable. + * @returns {Array} - The component logic. + */ get logic() { return this.component.logic || []; } /** * Check all triggers and apply necessary actions. - * - * @param data + * @param {any} data - The data to check against. + * @param {any} row - The row data to check against. + * @returns {boolean|void} - TRUE if the component was altered. */ - fieldLogic(data, row) { - data = data || this.rootValue; - row = row || this.data; + fieldLogic(data = this.rootValue, row = this.data) { const logics = this.logic; // If there aren't logic, don't go further. @@ -1989,6 +2198,10 @@ export default class Component extends Element { return changed; } + /** + * Retuns if the browser is Internet Explorer. + * @returns {boolean} - TRUE if the browser is IE. + */ isIE() { if (typeof window === 'undefined') { return false; @@ -2019,6 +2232,12 @@ export default class Component extends Element { return false; } + /** + * Defines the logic action value through evaluation. + * @param {object} action - The action within the Logic system to perform. + * @param {object} argsObject - The arguments to pass to the evaluation. + * @returns {any} - The result of the evaluation. + */ defineActionValue(action, argsObject) { return this.evaluate( action.value, @@ -2027,6 +2246,15 @@ export default class Component extends Element { ); } + /** + * Apply the actions of Logic for a component once the conditions have been met. + * @param {object} newComponent - The new component to apply the actions to. + * @param {Array} actions - An array of actions + * @param {any} result - The result of the conditional check in order to evaluate the actions. + * @param {any} row - The contextual row data for this component. + * @param {any} data - The global data object for the submission. + * @returns {boolean} - TRUE if the component was altered. + */ applyActions(newComponent, actions, result, row, data) { data = data || this.rootValue; row = row || this.data; @@ -2132,9 +2360,8 @@ export default class Component extends Element { /** * Add a new input error to this element. - * - * @param message - * @param dirty + * @param {Array|string} messages - An array of messages to add to the element. + * @returns {void} */ addMessages(messages) { if (!messages) { @@ -2166,6 +2393,15 @@ export default class Component extends Element { } } + /** + * Sets the form input widget error classes. + * @param {Array} elements - An array of DOM elements to set the error classes on. + * @param {boolean} dirty - If the input is dirty. + * @param {boolean} hasErrors - If the input has errors. + * @param {boolean} hasMessages - If the input has messages. + * @param {HTMLElement} element - The wrapper element for all the other elements passed in first argument. + * @returns {void} + */ setErrorClasses(elements, dirty, hasErrors, hasMessages, element = this.element) { this.clearErrorClasses(); elements.forEach((element) => { @@ -2195,6 +2431,12 @@ export default class Component extends Element { } } + /** + * Adds the classes necessary to mark an element as invalid. + * @param {HTMLElement} element - The element you wish to add the invalid classes to. + * @param {boolean} invalid - TRUE if the component is invalid, FALSE otherwise. + * @returns {void} + */ setElementInvalid(element, invalid) { if (!element) return; @@ -2207,6 +2449,9 @@ export default class Component extends Element { element.setAttribute('aria-invalid', invalid ? 'true' : 'false'); } + /** + * Clears the components data if it is conditionally hidden AND clearOnHide is set to true for this component. + */ clearOnHide() { // clearOnHide defaults to true for old forms (without the value set) so only trigger if the value is false. if ( @@ -2228,6 +2473,10 @@ export default class Component extends Element { } } + /** + * Triggers a debounced onChange event for the root component (usually Webform). + * @param {...any} args - The arguments to pass to the onChange event. + */ triggerRootChange(...args) { if (this.options.onChange) { this.options.onChange(...args); @@ -2237,6 +2486,13 @@ export default class Component extends Element { } } + /** + * Called when the component value has been changed. This will then trigger the root level onChange handler which + * propagates the checkData methods for the full component tree. + * @param {any} flags - The flags for the change event propagation. + * @param {boolean} fromRoot - If the change event is from the root component. + * @returns {boolean} - TRUE if the component has changed. + */ onChange(flags, fromRoot) { flags = flags || {}; if (flags.modified) { @@ -2390,7 +2646,7 @@ export default class Component extends Element { } this.quill = new Quill(element, isIEBrowser ? { ...settings, modules: {} } : settings); - /** This block of code adds the [source] capabilities. See https://codepen.io/anon/pen/ZyEjrQ **/ + /** This block of code adds the [source] capabilities. See https://codepen.io/anon/pen/ZyEjrQ */ const txtArea = document.createElement('textarea'); txtArea.setAttribute('class', 'quill-source-code'); this.quill.addContainer('ql-custom').appendChild(txtArea); @@ -2404,7 +2660,7 @@ export default class Component extends Element { txtArea.style.display = (txtArea.style.display === 'none') ? 'inherit' : 'none'; }); } - /** END CODEBLOCK **/ + /** END CODEBLOCK */ // Make sure to select cursor when they click on the element. this.addEventListener(element, 'click', () => this.quill.focus()); @@ -2458,8 +2714,7 @@ export default class Component extends Element { /** * The empty value for this component. - * - * @return {null} + * @returns {null} - The empty value for this component. */ get emptyValue() { return null; @@ -2467,7 +2722,8 @@ export default class Component extends Element { /** * Returns if this component has a value set. - * + * @param {any} data - The global data object. + * @returns {boolean} - TRUE if a value is set. */ hasValue(data) { return !_.isUndefined(_.get(data || this.data, this.key)); @@ -2475,8 +2731,7 @@ export default class Component extends Element { /** * Get the data value at the root level. - * - * @return {*} + * @returns {*} - The root value for the component, typically the Webform data object. */ get rootValue() { return this.root ? this.root.data : this.data; @@ -2488,7 +2743,7 @@ export default class Component extends Element { /** * Get the static value of this component. - * @return {*} + * @returns {*} - The value for this component. */ get dataValue() { if ( @@ -2509,8 +2764,7 @@ export default class Component extends Element { /** * Sets the static value of this component. - * - * @param value + * @param {*} value - The value to set for this component. */ set dataValue(value) { if ( @@ -2533,8 +2787,8 @@ export default class Component extends Element { /** * Splice a value from the dataValue. - * - * @param index + * @param {number} index - The index to splice for an array component values. + * @param {*} flags - The flags to use when splicing the value. */ splice(index, flags = {}) { if (this.hasValue()) { @@ -2617,8 +2871,7 @@ export default class Component extends Element { /** * Get the input value of this component. - * - * @return {*} + * @returns {*} - The value for the component. */ getValue() { if (!this.hasInput || this.viewOnly || !this.refs.input || !this.refs.input.length) { @@ -2642,9 +2895,8 @@ export default class Component extends Element { /** * Get the value at a specific index. - * - * @param index - * @returns {*} + * @param {number} index - For an array component or multiple values, this returns the value at a specific index. + * @returns {*} - The value at the specified index. */ getValueAt(index) { const input = this.performInputMapping(this.refs.input[index]); @@ -2653,11 +2905,9 @@ export default class Component extends Element { /** * Set the value of this component. - * - * @param value - * @param flags - * - * @return {boolean} - If the value changed. + * @param {*} value - The value to set for this component. + * @param {*} flags - The flags to use when setting the value. + * @returns {boolean} - If the value changed. */ setValue(value, flags = {}) { const changed = this.updateValue(value, flags); @@ -2691,9 +2941,9 @@ export default class Component extends Element { /** * Set the value at a specific index. - * - * @param index - * @param value + * @param {number} index - The index to set the value at. + * @param {*} value - The value to set at the specified index. + * @param {*} flags - The flags to use when setting the value. */ setValueAt(index, value, flags = {}) { if (!flags.noDefault && (value === null || value === undefined) && !this.component.multiple) { @@ -2747,9 +2997,8 @@ export default class Component extends Element { /** * Normalize values coming into updateValue. - * - * @param value - * @return {*} + * @param {*} value - The value to normalize before setting. + * @returns {*} - The normalized value. */ normalizeValue(value) { if (this.component.multiple && !Array.isArray(value)) { @@ -2760,8 +3009,9 @@ export default class Component extends Element { /** * Update a value of this component. - * - * @param flags + * @param {*} value - The value to update. + * @param {*} flags - The flags to use when updating the value. + * @returns {boolean} - If the value changed. */ updateComponentValue(value, flags = {}) { let newValue = (!flags.resetValue && (value === undefined || value === null)) ? this.getValue() : value; @@ -2781,9 +3031,8 @@ export default class Component extends Element { /** * Updates the value of this component plus all sub-components. - * - * @param args - * @return {boolean} + * @param {...any} args - The arguments to pass to updateValue. + * @returns {boolean} - If the value changed. */ updateValue(...args) { return this.updateComponentValue(...args); @@ -2812,10 +3061,9 @@ export default class Component extends Element { /** * Determine if the value of this component has changed. - * - * @param newValue - * @param oldValue - * @return {boolean} + * @param {*} newValue - The new value to check. + * @param {*} oldValue - The existing value of the component. + * @returns {boolean} - TRUE if the value has changed. */ hasChanged(newValue, oldValue) { if ( @@ -2838,8 +3086,9 @@ export default class Component extends Element { /** * Update the value on change. - * - * @param flags + * @param {*} flags - The flags to use when triggering the on change event. + * @param {boolean} changed - If the value has changed. + * @returns {boolean} - If the value changed. */ updateOnChange(flags = {}, changed = false) { if (!flags.noUpdateEvent && changed) { @@ -2853,14 +3102,6 @@ export default class Component extends Element { return false; } - /** - * Perform a calculated value operation. - * - * @param data - The global data object. - * - * @return {boolean} - If the value changed during calculation. - */ - convertNumberOrBoolToString(value) { if (typeof value === 'number' || typeof value === 'boolean' ) { return value.toString(); @@ -2989,9 +3230,10 @@ export default class Component extends Element { /** * Performs calculations in this component plus any child components. - * - * @param args - * @return {boolean} + * @param {*} data - The data to perform the calculation with. + * @param {*} flags - The flags to use when calculating the value. + * @param {*} row - The contextual row data to use when performing the calculation. + * @returns {boolean} - TRUE if the value changed. */ calculateValue(data, flags, row) { data = data || this.rootValue; @@ -3002,7 +3244,7 @@ export default class Component extends Element { /** * Get this component's label text. - * + * @returns {string} - The label text for this component. */ get label() { return this.component.label; @@ -3010,8 +3252,7 @@ export default class Component extends Element { /** * Set this component's label text and render it. - * - * @param value - The new label text. + * @param {string} value - The new label text. */ set label(value) { this.component.label = value; @@ -3022,7 +3263,7 @@ export default class Component extends Element { /** * Get FormioForm element at the root of this component tree. - * + * @returns {*} root - The root component to search from. */ getRoot() { return this.root; @@ -3030,10 +3271,11 @@ export default class Component extends Element { /** * Returns the invalid message, or empty string if the component is valid. - * - * @param data - * @param dirty - * @return {*} + * @param {*} data - The data to check if the component is valid. + * @param {boolean} dirty - If the component is dirty. + * @param {boolean} ignoreCondition - If conditions for the component should be ignored when checking validity. + * @param {*} row - Contextual row data for this component. + * @returns {string} - The message to show when the component is invalid. */ invalidMessage(data, dirty, ignoreCondition, row) { if (!ignoreCondition && !this.checkCondition(row, data)) { @@ -3070,10 +3312,9 @@ export default class Component extends Element { /** * Returns if the component is valid or not. - * - * @param data - * @param dirty - * @return {boolean} + * @param {*} data - The data to check if the component is valid. + * @param {boolean} dirty - If the component is dirty. + * @returns {boolean} - TRUE if the component is valid. */ isValid(data, dirty) { return !this.invalidMessage(data, dirty); @@ -3094,8 +3335,8 @@ export default class Component extends Element { /** * Interpolate errors from the validation methods. - * @param {*} errors - * @returns + * @param {Array} errors - An array of errors to interpolate. + * @returns {Array} - The interpolated errors. */ interpolateErrors(errors) { const interpolatedErrors = FormioUtils.interpolateErrors(this.component, errors, this.t.bind(this)); @@ -3108,7 +3349,7 @@ export default class Component extends Element { * @param {*} data - The root submission data. * @param {*} row - The contextual row data. * @param {*} flags - The flags to perform validation. - * @returns + * @returns {boolean} - TRUE if the component is valid. */ showValidationErrors(errors, data, row, flags) { if (flags.silentCheck) { @@ -3129,7 +3370,7 @@ export default class Component extends Element { * @param {*} data - The root data you wish to use for this component. * @param {*} row - The contextual row data you wish to use for this component. * @param {*} flags - The flags to control the behavior of the validation. - * @returns + * @returns {Array} - An array of errors if the component is invalid. */ validateComponent(data, row, flags = {}) { data = data || this.rootValue; @@ -3164,11 +3405,12 @@ export default class Component extends Element { /** * Checks the validity of this component and sets the error message if it is invalid. - * - * @param data - * @param dirty - * @param row - * @return {boolean} + * @param {*} data - The data to check if the component is valid. + * @param {boolean} dirty - If the component is dirty. + * @param {*} row - The contextual row data for this component. + * @param {*} flags - The flags to use when checking the validity. + * @param {Array} allErrors - An array of all errors that have occured so that it can be appended when another one occurs here. + * @returns {boolean} - TRUE if the component is valid. */ checkComponentValidity(data, dirty, row, flags = {}, allErrors = []) { data = data || this.rootValue; @@ -3207,11 +3449,12 @@ export default class Component extends Element { /** * Checks the validity of the component. - * @param {*} data - * @param {*} dirty - * @param {*} row - * @param {*} silentCheck - * @returns + * @param {*} data - The data to check if the component is valid. + * @param {boolean} dirty - If the component is dirty. + * @param {*} row - The contextual row data for this component. + * @param {boolean} silentCheck - If the check should be silent and not set the error messages. + * @param {Array} errors - An array of all errors that have occured so that it can be appended when another one occurs here. + * @returns {boolean} - TRUE if the component is valid. */ checkValidity(data, dirty, row, silentCheck, errors = []) { data = data || this.rootValue; @@ -3228,11 +3471,10 @@ export default class Component extends Element { /** * Check the conditions, calculations, and validity of a single component and triggers an update if * something changed. - * - * @param data - The root data of the change event. - * @param flags - The flags from this change event. - * - * @return boolean - If component is valid or not. + * @param {*} data - The root data of the change event. + * @param {*} flags - The flags from this change event. + * @param {*} row - The contextual row data for this component. + * @returns {void|boolean} - TRUE if no check should be performed on the component. */ checkData(data, flags, row) { data = data || this.rootValue; @@ -3287,8 +3529,7 @@ export default class Component extends Element { /** * Check if a component is eligible for multiple validation - * - * @return {boolean} + * @returns {boolean} - TRUE if the component is eligible for multiple validation. */ validateMultiple() { return true; @@ -3419,8 +3660,7 @@ export default class Component extends Element { /** * Determines if the value of this component is hidden from the user as if it is coming from the server, but is * protected. - * - * @return {boolean|*} + * @returns {boolean|*} - TRUE if the value is hidden. */ isValueHidden() { if (this.component.protected && this.root.editing) { @@ -3470,6 +3710,8 @@ export default class Component extends Element { /** * Prints out the value of this component as a string value. + * @param {*} value - The value to print out. + * @returns {string} - The string representation of the value. */ asString(value) { value = value || this.getValue(); @@ -3478,7 +3720,7 @@ export default class Component extends Element { /** * Return if the component is disabled. - * @return {boolean} + * @returns {boolean} - TRUE if the component is disabled. */ get disabled() { return this._disabled || this.parentDisabled; @@ -3486,8 +3728,7 @@ export default class Component extends Element { /** * Disable this component. - * - * @param {boolean} disabled + * @param {boolean} disabled - TRUE to disable the component. */ set disabled(disabled) { this._disabled = disabled; @@ -3627,6 +3868,7 @@ export default class Component extends Element { /** * Get the element information. + * @returns {*} - The components "input" DOM element information. */ elementInfo() { const attributes = { @@ -3707,6 +3949,7 @@ export default class Component extends Element { /** * Get `Formio` instance for working with files + * @returns {import('@formio/core').Formio} - The Formio instance file service. */ get fileService() { if (this.options.fileService) { diff --git a/src/components/_classes/component/editForm/Component.edit.display.js b/src/components/_classes/component/editForm/Component.edit.display.js index b6159d9df6..3e6e76d865 100644 --- a/src/components/_classes/component/editForm/Component.edit.display.js +++ b/src/components/_classes/component/editForm/Component.edit.display.js @@ -187,13 +187,5 @@ export default [ key: 'tableView', input: true }, - { - weight: 1600, - type: 'checkbox', - label: 'Modal Edit', - tooltip: 'Opens up a modal to edit the value of this component.', - key: 'modalEdit', - input: true - }, ]; /* eslint-enable max-len */ diff --git a/src/components/_classes/field/Field.js b/src/components/_classes/field/Field.js index 5bc4a52ef4..fefa52f60c 100644 --- a/src/components/_classes/field/Field.js +++ b/src/components/_classes/field/Field.js @@ -1,6 +1,14 @@ import Component from '../component/Component'; +/* + * Field class is a base class for all fields. + * @extends Component + */ export default class Field extends Component { + /** + * @param {object} element - The component to create. + * @returns {Field} - The created field. + */ render(element) { if (this.noField) { return super.render(element); @@ -20,7 +28,11 @@ export default class Field extends Component { } } - // Saves current caret position to restore it after the component is redrawn + /** + /* Saves current caret position to restore it after the component is redrawn + * @param {HTMLElement} element - The element to save the caret position for. + * @param {number} index - The index of the element. + */ saveCaretPosition(element, index) { if (this.root?.focusedComponent?.path === this.path) { try { diff --git a/src/components/_classes/input/Input.js b/src/components/_classes/input/Input.js index ba3ba94fda..da00bf956e 100644 --- a/src/components/_classes/input/Input.js +++ b/src/components/_classes/input/Input.js @@ -276,8 +276,8 @@ export default class Input extends Multivalue { /** * Creates an instance of a widget for this component. - * - * @return {null} + * @param {number} index - The index of the widget. + * @returns {*} - The widget instance. */ createWidget(index) { // Return null if no widget is found. diff --git a/src/components/_classes/list/ListComponent.form.js b/src/components/_classes/list/ListComponent.form.js index e0cca99f24..e5ac577a6d 100644 --- a/src/components/_classes/list/ListComponent.form.js +++ b/src/components/_classes/list/ListComponent.form.js @@ -1,6 +1,11 @@ import Components from '../../Components'; import ListEditData from './editForm/ListComponent.edit.data'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return Components.baseEditForm([ { diff --git a/src/components/_classes/multivalue/Multivalue.js b/src/components/_classes/multivalue/Multivalue.js index 03e8d971c4..8eb14de301 100644 --- a/src/components/_classes/multivalue/Multivalue.js +++ b/src/components/_classes/multivalue/Multivalue.js @@ -38,6 +38,9 @@ export default class Multivalue extends Field { return this.component.hasOwnProperty('multiple') && this.component.multiple; } + /** + * @returns {Field} - The created field. + */ render() { // If single value field. if (!this.useWrapper()) { @@ -68,6 +71,12 @@ export default class Multivalue extends Field { return ''; } + /** + * Renders a single row for multi-value components. + * @param {any} value - The value associated with the row to render. + * @param {number} index - The index of the row in the multi-value list. + * @returns {any} Returns the HTML string representation of the row. + */ renderRow(value, index) { return this.renderTemplate('multiValueRow', { index, @@ -76,6 +85,10 @@ export default class Multivalue extends Field { }); } + /** + * @param {HTMLElement} dom - The DOM element to which the component will attach. + * @returns {Promise} - Promise that resolves when all asynchronous tasks that have finished. + */ attach(dom) { const superAttach = super.attach(dom); this.loadRefs(dom, { @@ -115,6 +128,10 @@ export default class Multivalue extends Field { }); } + + /** + * Remove all event handlers. + */ detach() { if (this.refs.input && this.refs.input.length) { this.refs.input.forEach((input) => { @@ -138,9 +155,8 @@ export default class Multivalue extends Field { /** * Attach inputs to the element. - * - * @param element - * @param index + * @param {HTMLElement} element - The element to attach. + * @param {number} index - The index of the element to attach. */ attachElement(element, index) { this.addEventListener(element, this.inputInfo.changeEvent, () => { @@ -215,10 +231,19 @@ export default class Multivalue extends Field { } } + /** + * Event handler for selecting a mask from a dropdown. + * @param {Event} event - Event triggered by changing the selected option in mask. + */ onSelectMaskHandler(event) { this.updateMask(event.target.maskInput, this.getMaskPattern(event.target.value)); } + /** + * Retrieves the mask pattern for a given mask name + * @param {string} maskName - The name of the mask to retrieve. + * @returns {any} The mask pattern associated with the given mask name. + */ getMaskPattern(maskName) { if (!this.multiMasks) { this.multiMasks = {}; @@ -231,6 +256,11 @@ export default class Multivalue extends Field { return this.multiMasks[maskName]; } + /** + * Attaches a selectable mask to an input field based on its configuration. + * @param {number} index - The index of the select or input in component array. + * @returns {boolean} - Returns true if the mask was successfully attached + */ attachMultiMask(index) { if (!(this.isMultipleMasksField && this.component.inputMasks.length && this.refs.input.length)) { return false; @@ -243,6 +273,10 @@ export default class Multivalue extends Field { return true; } + /** + * @param {any} input - The input element on which the mask is to be applied. + * @param {string} mask - The mask pattern to apply to the input element. Exit early if no mask. + */ updateMask(input, mask) { if (!mask) { return; @@ -253,6 +287,7 @@ export default class Multivalue extends Field { /** * Adds a new empty value to the data array. + * @param {any} value -A value to be added to the data array. */ addNewValue(value) { if (value === undefined) { diff --git a/src/components/_classes/nested/NestedComponent.form.js b/src/components/_classes/nested/NestedComponent.form.js index 5795262cfb..e0f5da1532 100644 --- a/src/components/_classes/nested/NestedComponent.form.js +++ b/src/components/_classes/nested/NestedComponent.form.js @@ -1,5 +1,10 @@ import Components from '../../Components'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return Components.baseEditForm([ { diff --git a/src/components/_classes/nested/NestedComponent.js b/src/components/_classes/nested/NestedComponent.js index 188d367274..e95612489d 100644 --- a/src/components/_classes/nested/NestedComponent.js +++ b/src/components/_classes/nested/NestedComponent.js @@ -3,9 +3,12 @@ import _ from 'lodash'; import Field from '../field/Field'; import Components from '../../Components'; import { getArrayFromComponentPath, getStringFromComponentPath, getRandomComponentId } from '../../../utils/utils'; -import Component from '../component/Component'; import { process as processAsync, processSync } from '@formio/core/process'; +/** + * NestedComponent class. + * @augments Field + */ export default class NestedComponent extends Field { static schema(...extend) { return Field.schema({ @@ -17,6 +20,12 @@ export default class NestedComponent extends Field { constructor(component, options, data) { super(component, options, data); this.type = 'components'; + /** + * The collapsed state of this NestedComponent. + * @type {boolean} + * @default false + * @private + */ this._collapsed = !!this.component.collapsed; } @@ -24,17 +33,30 @@ export default class NestedComponent extends Field { return NestedComponent.schema(); } + /** + * Get the schema for the NestedComponent. + * @returns {object} The schema for the NestedComponent. + * @override + */ get schema() { const schema = super.schema; const components = _.uniqBy(this.getComponents(), 'component.key'); schema.components = _.map(components, 'schema'); return schema; } - + /** + * Get collapsed state. + * @returns {boolean} The collapsed state. + */ get collapsed() { return this._collapsed; } + /** + * Set collapsed state. + * @param {boolean} value - The collapsed state. + * @returns {void} + */ collapse(value) { const promise = this.redraw(); if (!value) { @@ -43,11 +65,20 @@ export default class NestedComponent extends Field { return promise; } + /** + * Set collapsed state. + * @param {boolean} value - The collapsed state. + * @returns {void} + */ set collapsed(value) { this._collapsed = value; this.collapse(value); } - + /** + * Set visible state of parent and each child component. + * @param {boolean} value - The visible state. + * @returns {void} + */ set visible(value) { // DO NOT CALL super here. There is an issue where clearOnHide was getting triggered with // subcomponents because the "parentVisible" flag was set to false when it should really be @@ -80,28 +111,54 @@ export default class NestedComponent extends Field { } } + /** + * Get visible state. + * @returns {boolean} The visible state. + */ get visible() { return super.visible; } + /** + * Set parent visibility. + * @param {boolean} value - The parent visibility. + * @returns {void} + */ set parentVisible(value) { super.parentVisible = value; this.components.forEach(component => component.parentVisible = this.visible); } + /** + * Get parent visibility. + * @returns {boolean} The parent visibility. + */ get parentVisible() { return super.parentVisible; } + /** + * Get the disabled state. + * @returns {boolean} - The disabled state. + */ get disabled() { return super.disabled; } + /** + * Set the disabled state. + * @param {boolean} disabled - The disabled state. + */ set disabled(disabled) { super.disabled = disabled; this.components.forEach((component) => component.parentDisabled = disabled); } + /** + * Set parent disabled state. + * @param {boolean} value - The parent disabled state. + * @returns {void} + */ set parentDisabled(value) { super.parentDisabled = value; this.components.forEach(component => { @@ -109,18 +166,35 @@ export default class NestedComponent extends Field { }); } + /** + * Get parent disabled state. + * @returns {boolean} The parent disabled state. + */ get parentDisabled() { return super.parentDisabled; } + /** + * Get ready state from all components. + * @returns {Promise} - The promise that resolves when all components are ready. + */ get ready() { return Promise.all(this.getComponents().map(component => component.ready)); } + /** + * Get currentForm object. + * @returns {object} - The current form object. + */ get currentForm() { return super.currentForm; } + /** + * Set currentForm object. + * @param {object} instance - The current form object. + * @returns {void} + */ set currentForm(instance) { super.currentForm = instance; this.getComponents().forEach(component => { @@ -128,10 +202,19 @@ export default class NestedComponent extends Field { }); } + /** + * Get Row Index. + * @returns {number} - The row index. + */ get rowIndex() { return this._rowIndex; } + /** + * Set Row Index to row and update each component. + * @param {number} value - The row index. + * @returns {void} + */ set rowIndex(value) { this._rowIndex = value; this.eachComponent((component) => { @@ -139,14 +222,29 @@ export default class NestedComponent extends Field { }); } + /** + * Get Contextual data of the component. + * @returns {object} - The contextual data of the component. + * @override + */ componentContext() { return this._data; } + /** + * Get the data of the component. + * @returns {object} - The data of the component. + * @override + */ get data() { return this._data; } + /** + * Set the data of the component. + * @param {object} value - The data of the component. + * @returns {void} + */ set data(value) { this._data = value; this.eachComponent((component) => { @@ -154,6 +252,10 @@ export default class NestedComponent extends Field { }); } + /** + * Get components array. + * @returns {Array} - The components array. + */ getComponents() { return this.components || []; } @@ -161,8 +263,8 @@ export default class NestedComponent extends Field { /** * Perform a deep iteration over every component, including those * within other container based components. - * - * @param {function} fn - Called for every component. + * @param {Function} fn - Called for every component. + * @param {any} options - The options to include with this everyComponent call. */ everyComponent(fn, options) { const components = this.getComponents(); @@ -179,6 +281,11 @@ export default class NestedComponent extends Field { }); } + /** + * Check if the component has a component. + * @param {import('@formio/core').Component} component - The component to check. + * @returns {boolean} - TRUE if the component has a component, FALSE otherwise. + */ hasComponent(component) { let result = false; @@ -192,6 +299,10 @@ export default class NestedComponent extends Field { return result; } + /** + * Get the flattened components of this NestedComponent. + * @returns {object} - The flattened components of this NestedComponent. + */ flattenComponents() { const result = {}; @@ -204,8 +315,7 @@ export default class NestedComponent extends Field { /** * Perform an iteration over each component within this container component. - * - * @param {function} fn - Called for each component + * @param {Function} fn - Called for each component */ eachComponent(fn) { _.each(this.getComponents(), (component, index) => { @@ -218,11 +328,10 @@ export default class NestedComponent extends Field { /** * Returns a component provided a key. This performs a deep search within the * component tree. - * - * @param {string} key - The key of the component to retrieve. - * @param {function} [fn] - Called with the component once found. + * @param {string} path - The path to the component. + * @param {Function} [fn] - Called with the component once found. * @param {string} [originalPath] - The original path to the component. - * @return {Component} - The component that is located. + * @returns {any} - The component that is located. */ getComponent(path, fn, originalPath) { originalPath = originalPath || getStringFromComponentPath(path); @@ -277,10 +386,9 @@ export default class NestedComponent extends Field { /** * Return a component provided the Id of the component. - * * @param {string} id - The Id of the component. - * @param {function} fn - Called with the component once it is retrieved. - * @return {Object} - The component retrieved. + * @param {Function} fn - Called with the component once it is retrieved. + * @returns {object} - The component retrieved. */ getComponentById(id, fn) { let comp = null; @@ -298,9 +406,12 @@ export default class NestedComponent extends Field { /** * Create a new component and add it to the components array. - * - * @param component - * @param data + * @param {import('@formio/core').Component} component - The component JSON schema to create. + * @param {object} options - The options to create the component with. + * @param {import('@formio/core').DataObject} data - The submission data object to house the data for this component. + * @param {import('@formio/core').Component} [before] - The component before which to add this component. + * @param {import('@formio/core').Component} [replacedComp] - The component to replace with this component. + * @returns {any} - The created component instance. */ createComponent(component, options, data, before, replacedComp) { if (!component) { @@ -369,9 +480,9 @@ export default class NestedComponent extends Field { } /** - * - * @param element - * @param data + * Add a new component instance to the components array. + * @param {import('@formio/core').DataObject} [data] - The Submission data for this component. + * @param {object} [options] - The options for this component. */ addComponents(data, options) { data = data || this.data; @@ -388,11 +499,11 @@ export default class NestedComponent extends Field { /** * Add a new component to the components array. - * - * @param {Object} component - The component JSON schema to add. - * @param {Object} data - The submission data object to house the data for this component. + * @param {import('@formio/core').Component} component - The component JSON schema to add. + * @param {object} data - The submission data object to house the data for this component. * @param {HTMLElement} before - A DOM element to insert this element before. - * @return {Component} - The created component instance. + * @param {boolean} [noAdd] - A possibly extraneous boolean flag. + * @returns {any} - The created component instance. */ addComponent(component, data, before, noAdd) { data = data || this.data; @@ -465,6 +576,10 @@ export default class NestedComponent extends Field { ]); } + /** + * Attach the logic to the components. + * @param {import('@formio/core').Component[]} components - The components to attach logic to. + */ attachComponentsLogic(components) { components = components || this.components; @@ -500,9 +615,9 @@ export default class NestedComponent extends Field { /** * Remove a component from the components array and from the children object - * - * @param {Component} component - The component to remove from the components. - * @param {Array} components - An array of components to remove this component from. + * @param {import('@formio/core').Component} component - The component to remove from the components. + * @param {import('@formio/core').Component[]} components - An array of components to remove this component from. + * @param {boolean} [all] - If set to TRUE will cascade remove all components. */ removeComponent(component, components, all = false) { components = components || this.components; @@ -515,10 +630,9 @@ export default class NestedComponent extends Field { /** * Removes a component provided the API key of that component. - * * @param {string} key - The API key of the component to remove. - * @param {function} fn - Called once the component is removed. - * @return {null} + * @param {Function} fn - Called once the component is removed. + * @returns {null|void} - Returns nothing if the component is not found. */ removeComponentByKey(key, fn) { const comp = this.getComponent(key, (component, components) => { @@ -537,10 +651,9 @@ export default class NestedComponent extends Field { /** * Removes a component provided the Id of the component. - * * @param {string} id - The Id of the component to remove. - * @param {function} fn - Called when the component is removed. - * @return {null} + * @param {Function} fn - Called when the component is removed. + * @returns {null|void} - Returns nothing if the component is not found. */ removeComponentById(id, fn) { const comp = this.getComponentById(id, (component, components) => { @@ -612,8 +725,8 @@ export default class NestedComponent extends Field { /** * Allow components to hook into the next page trigger to perform their own logic. - * - * @return {*} + * @param {Function} next - The callback to continue to the next page. + * @returns {Promise} - A promise when the page has been processed. */ beforePage(next) { return Promise.all(this.getComponents().map((comp) => comp.beforePage(next))); @@ -621,8 +734,7 @@ export default class NestedComponent extends Field { /** * Allow components to hook into the submission to provide their own async data. - * - * @return {*} + * @returns {Promise} - Returns a promise when the constituent beforeSubmit functions are complete. */ beforeSubmit() { return Promise.allSettled(this.getComponents().map((comp) => comp.beforeSubmit())); @@ -663,10 +775,10 @@ export default class NestedComponent extends Field { /** * Perform a validation on all child components of this nested component. - * @param {*} components - * @param {*} data - * @param {*} flags - * @returns + * @param {import('@formio/core').Component[]} components - The components to validate. + * @param {import('@formio/core').DataObject} data - The data to validate. + * @param {object} flags - The flags to use when validating. + * @returns {Promise|Array} - The errors if any exist. */ validateComponents(components, data, flags = {}) { components = components || this.component.components; @@ -706,9 +818,9 @@ export default class NestedComponent extends Field { /** * Validate a nested component with data, or its own internal data. - * @param {*} data - * @param {*} flags - * @returns + * @param {import('@formio/core').DataObject} data - The data to validate. + * @param {object} flags - The flags to use when validating. + * @returns {Array} - The errors if any exist. */ validate(data, flags = {}) { data = data || this.rootValue; diff --git a/src/components/_classes/nesteddata/NestedDataComponent.js b/src/components/_classes/nesteddata/NestedDataComponent.js index c6a4271c72..1ff0ee375a 100644 --- a/src/components/_classes/nesteddata/NestedDataComponent.js +++ b/src/components/_classes/nesteddata/NestedDataComponent.js @@ -121,8 +121,7 @@ export default class NestedDataComponent extends NestedComponent { /** * Get the value of this component. - * - * @returns {*} + * @returns {any} - Return the value of this component. */ getValue() { return this.dataValue; diff --git a/src/components/address/Address.form.js b/src/components/address/Address.form.js index aae69d7cd5..aa9a206207 100644 --- a/src/components/address/Address.form.js +++ b/src/components/address/Address.form.js @@ -3,6 +3,11 @@ import AddressEditData from './editForm/Address.edit.data'; import AddressEditDisplay from './editForm/Address.edit.display'; import AddressEditProvider from './editForm/Address.edit.provider'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return Components.baseEditForm([ { diff --git a/src/components/button/Button.form.js b/src/components/button/Button.form.js index 1a7d2099ff..6e15574b9a 100644 --- a/src/components/button/Button.form.js +++ b/src/components/button/Button.form.js @@ -1,6 +1,11 @@ import Components from '../Components'; import ButtonEditDisplay from './editForm/Button.edit.display'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return Components.baseEditForm([ { diff --git a/src/components/button/Button.js b/src/components/button/Button.js index 7194c10e1a..0505f9fdd1 100644 --- a/src/components/button/Button.js +++ b/src/components/button/Button.js @@ -253,6 +253,11 @@ export default class ButtonComponent extends Field { this.disabled = this.shouldDisabled; this.setDisabled(this.refs.button, this.disabled); + /** + * Get url parameter by name + * @param {string} name - The url parameter + * @returns {string} - The url parameter value + */ function getUrlParameter(name) { name = name.replace(/[[]/, '\\[').replace(/[\]]/, '\\]'); const regex = new RegExp(`[\\?&]${name}=([^&#]*)`); diff --git a/src/components/checkbox/Checkbox.form.js b/src/components/checkbox/Checkbox.form.js index 2eca29b217..6af6796817 100644 --- a/src/components/checkbox/Checkbox.form.js +++ b/src/components/checkbox/Checkbox.form.js @@ -3,6 +3,11 @@ import CheckboxEditData from './editForm/Checkbox.edit.data'; import CheckboxEditDisplay from './editForm/Checkbox.edit.display'; import CheckboxEditValidation from './editForm/Checkbox.edit.validation'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return Components.baseEditForm([ { diff --git a/src/components/columns/Columns.form.js b/src/components/columns/Columns.form.js index 76bac20a96..5bed40f9b2 100644 --- a/src/components/columns/Columns.form.js +++ b/src/components/columns/Columns.form.js @@ -2,6 +2,11 @@ import nestedComponentForm from '../_classes/nested/NestedComponent.form'; import ColumnsEditDisplay from './editForm/Columns.edit.display'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return nestedComponentForm([ { diff --git a/src/components/columns/Columns.js b/src/components/columns/Columns.js index 67bddaed06..92ccbce8f1 100644 --- a/src/components/columns/Columns.js +++ b/src/components/columns/Columns.js @@ -134,7 +134,7 @@ export default class ColumnsComponent extends NestedComponent { /** * Group columns in rows. - * @return {Array.} + * @returns {Array.} - The array of columns */ groupByRow() { const initVal = { stack: [], rows: [] }; diff --git a/src/components/container/Container.form.js b/src/components/container/Container.form.js index 75755ed07f..6ccefc84fc 100644 --- a/src/components/container/Container.form.js +++ b/src/components/container/Container.form.js @@ -2,6 +2,11 @@ import Components from '../Components'; import ContainerEditDisplay from './editForm/Container.edit.display'; import ContainerEditData from './editForm/Container.edit.data'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return Components.baseEditForm([ { diff --git a/src/components/content/Content.form.js b/src/components/content/Content.form.js index b81c82cd24..3e11a5a4e3 100644 --- a/src/components/content/Content.form.js +++ b/src/components/content/Content.form.js @@ -2,6 +2,11 @@ import Components from '../Components'; import ContentEditDisplay from './editForm/Content.edit.display'; import ContentEditLogic from './editForm/Content.edit.logic'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { const editForm = Components.baseEditForm([ { diff --git a/src/components/currency/Currency.form.js b/src/components/currency/Currency.form.js index 2bfc648ab5..23d0b9924e 100644 --- a/src/components/currency/Currency.form.js +++ b/src/components/currency/Currency.form.js @@ -1,6 +1,11 @@ import baseEditForm from '../textfield/TextField.form'; import CurrencyEditDisplay from './editForm/Currency.edit.display'; import CurrencyEditData from './editForm/Currency.edit.data'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return baseEditForm([ { diff --git a/src/components/currency/Currency.js b/src/components/currency/Currency.js index 0356ca2b32..dce69bbde5 100644 --- a/src/components/currency/Currency.js +++ b/src/components/currency/Currency.js @@ -34,8 +34,7 @@ export default class CurrencyComponent extends NumberComponent { /** * Creates the number mask for currency numbers. - * - * @return {*} + * @returns {*} - The result of the createNumberMask function */ createNumberMask() { const decimalLimit = _.get(this.component, 'decimalLimit', 2); diff --git a/src/components/datagrid/DataGrid.form.js b/src/components/datagrid/DataGrid.form.js index 6e7218674b..229c2385f0 100644 --- a/src/components/datagrid/DataGrid.form.js +++ b/src/components/datagrid/DataGrid.form.js @@ -3,6 +3,11 @@ import DataGridEditData from './editForm/DataGrid.edit.data'; import DataGridEditDisplay from './editForm/DataGrid.edit.display'; import DataGridEditValidation from './editForm/DataGrid.edit.validation'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return Components.baseEditForm([ { diff --git a/src/components/datagrid/DataGrid.js b/src/components/datagrid/DataGrid.js index fa029029ca..fef44a671a 100644 --- a/src/components/datagrid/DataGrid.js +++ b/src/components/datagrid/DataGrid.js @@ -162,9 +162,9 @@ export default class DataGridComponent extends NestedArrayComponent { /** * Split rows into chunks. - * @param {Number[]} groups - array of numbers where each item is size of group + * @param {number[]} groups - array of numbers where each item is size of group * @param {Array} rows - rows collection - * @return {Array} + * @returns {Array} - The chunked rows */ getRowChunks(groups, rows) { const [, chunks] = groups.reduce( @@ -179,7 +179,7 @@ export default class DataGridComponent extends NestedArrayComponent { /** * Create groups object. * Each key in object represents index of first row in group. - * @return {Object} + * @returns {object} - The groups object. */ getGroups() { const groups = _.get(this.component, 'rowGroups', []); @@ -201,8 +201,8 @@ export default class DataGridComponent extends NestedArrayComponent { } /** - * Retrun group sizes. - * @return {Number[]} + * Get group sizes. + * @returns {number[]} - The array of group sizes. */ getGroupSizes() { return _.map(_.get(this.component, 'rowGroups', []), 'numberOfRows'); diff --git a/src/components/datamap/DataMap.form.js b/src/components/datamap/DataMap.form.js index 2967af769f..47e8ec077d 100644 --- a/src/components/datamap/DataMap.form.js +++ b/src/components/datamap/DataMap.form.js @@ -2,6 +2,11 @@ import Components from '../Components'; import DataMapEditData from './editForm/DataMap.edit.data'; import DataMapEditDisplay from './editForm/DataMap.edit.display'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return Components.baseEditForm([ { diff --git a/src/components/datetime/DateTime.form.js b/src/components/datetime/DateTime.form.js index 5a616bd478..5536d60913 100644 --- a/src/components/datetime/DateTime.form.js +++ b/src/components/datetime/DateTime.form.js @@ -5,6 +5,11 @@ import DateTimeEditDisplay from './editForm/DateTime.edit.display'; import DateTimeEditTime from './editForm/DateTime.edit.time'; import DateTimeEditValidation from './editForm/DateTime.edit.validation'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return Components.baseEditForm([ { diff --git a/src/components/day/Day.form.js b/src/components/day/Day.form.js index 928696ad30..cb7de71193 100644 --- a/src/components/day/Day.form.js +++ b/src/components/day/Day.form.js @@ -6,6 +6,11 @@ import DayEditDay from './editForm/Day.edit.day'; import DayEditMonth from './editForm/Day.edit.month'; import DayEditYear from './editForm/Day.edit.year'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return Components.baseEditForm([ { diff --git a/src/components/day/Day.js b/src/components/day/Day.js index 397931d3d9..9b1bf9a869 100644 --- a/src/components/day/Day.js +++ b/src/components/day/Day.js @@ -69,8 +69,7 @@ export default class DayComponent extends Field { /** * The empty value for day component. - * - * @return {'00/00/0000'} + * @returns {'00/00/0000'} - The empty value of the day component. */ get emptyValue() { return '00/00/0000'; @@ -406,10 +405,10 @@ export default class DayComponent extends Field { } /** - * Set the value at a specific index. - * - * @param index - * @param value + * Set the value at a specific index and updates the component's refs. + * @param {number} index - The index to set. + * @param {any} value - The value to set. + * @returns {null|void} - Returns null if the value is invalid, otherwise void. */ setValueAt(index, value) { // temporary solution to avoid input reset @@ -469,7 +468,7 @@ export default class DayComponent extends Field { /** * Get the format for the value string. - * @returns {string} + * @returns {string} - the format for the value string. */ get format() { let format = ''; @@ -494,9 +493,8 @@ export default class DayComponent extends Field { /** * Return the date for this component. - * - * @param value - * @return {*} + * @param {any} value - The value to convert to a date. + * @returns {null|string} - The date string. */ getDate(value) { let defaults = [], day, month, year; @@ -550,8 +548,8 @@ export default class DayComponent extends Field { } /** - * Return the date object for this component. - * @returns {Date} + * Return the date string for this component. + * @returns {string|null} - The date string for this component. */ get date() { return this.getDate(); @@ -559,8 +557,7 @@ export default class DayComponent extends Field { /** * Return the raw value. - * - * @returns {Date} + * @returns {string} - The raw value of the component. */ get validationValue() { return this.dataValue; @@ -573,9 +570,8 @@ export default class DayComponent extends Field { /** * Get the value at a specific index. - * - * @param index - * @returns {*} + * @param {number} index - The index to get the value from. + * @returns {*} - The value at index. */ getValueAt(index) { const date = this.date || this.emptyValue; @@ -591,9 +587,8 @@ export default class DayComponent extends Field { /** * Get the input value of the date. - * - * @param value - * @return {null} + * @param {any} value - The value to convert to a string. + * @returns {string|null} - The string value of the date. */ getValueAsString(value) { return this.getDate(value) || ''; diff --git a/src/components/editgrid/EditGrid.form.js b/src/components/editgrid/EditGrid.form.js index caa0e655ba..b9cd131562 100644 --- a/src/components/editgrid/EditGrid.form.js +++ b/src/components/editgrid/EditGrid.form.js @@ -4,6 +4,11 @@ import EditGridEditDisplay from './editForm/EditGrid.edit.display'; import EditGridEditTemplates from './editForm/EditGrid.edit.templates'; import EditGridEditValidation from './editForm/EditGrid.edit.validation'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return Components.baseEditForm([ { diff --git a/src/components/editgrid/EditGrid.js b/src/components/editgrid/EditGrid.js index 500e09fbf6..1a0bd058ee 100644 --- a/src/components/editgrid/EditGrid.js +++ b/src/components/editgrid/EditGrid.js @@ -182,8 +182,8 @@ export default class EditGridComponent extends NestedArrayComponent { } /** - * Returns true if the component has nested components which don't trigger changes on the root level - */// + * @returns {boolean} - Returns true if the component has nested components which don't trigger changes on the root level + */ get hasScopedChildren() { return !this.inlineEditMode; } @@ -1228,7 +1228,7 @@ export default class EditGridComponent extends NestedArrayComponent { } /** - * Return that this component processes its own validation. + * @returns {boolean} - Return that this component processes its own validation. */ get processOwnValidation() { return true; diff --git a/src/components/email/Email.form.js b/src/components/email/Email.form.js index 12258dd955..4f7707d8e0 100644 --- a/src/components/email/Email.form.js +++ b/src/components/email/Email.form.js @@ -2,6 +2,11 @@ import baseEditForm from '../textfield/TextField.form'; import EmailEditFormDisplay from './editForm/Email.edit.display'; import EmailEditFormValidation from './editForm/Email.edit.validation'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return baseEditForm([ { diff --git a/src/components/fieldset/Fieldset.form.js b/src/components/fieldset/Fieldset.form.js index 8ac01aeaf8..7bbe8af81a 100644 --- a/src/components/fieldset/Fieldset.form.js +++ b/src/components/fieldset/Fieldset.form.js @@ -1,5 +1,10 @@ import nestedComponentForm from '../_classes/nested/NestedComponent.form'; import FieldSetEditDisplay from './editForm/Fieldset.edit.display'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return nestedComponentForm([ { diff --git a/src/components/file/File.form.js b/src/components/file/File.form.js index 686005eb02..fbdaa6e747 100644 --- a/src/components/file/File.form.js +++ b/src/components/file/File.form.js @@ -4,6 +4,11 @@ import FileEditDisplay from './editForm/File.edit.display'; import FileEditFile from './editForm/File.edit.file'; import FileEditValidation from './editForm/File.edit.validation'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return Components.baseEditForm([ { diff --git a/src/components/form/Form.form.js b/src/components/form/Form.form.js index 5edcd85f8f..a9faf554f9 100644 --- a/src/components/form/Form.form.js +++ b/src/components/form/Form.form.js @@ -3,6 +3,11 @@ import FormEditDisplay from './editForm/Form.edit.display'; import FormEditForm from './editForm/Form.edit.form'; import FormEditData from './editForm/Form.edit.data'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return nestedComponentForm([ { diff --git a/src/components/form/Form.js b/src/components/form/Form.js index 04cab1613d..6be3099ed3 100644 --- a/src/components/form/Form.js +++ b/src/components/form/Form.js @@ -397,8 +397,8 @@ export default class FormComponent extends Component { /** * Pass everyComponent to subform. - * @param args - * @returns {*|void} + * @param {any[]} args - Arguments to pass through to the subform's everyComponent method. + * @returns {*} - The result of the subform's everyComponent method. */ everyComponent(...args) { if (this.subForm) { @@ -425,8 +425,8 @@ export default class FormComponent extends Component { /** * Create a subform instance. - * - * @return {*} + * @param {boolean} [fromAttach] - This function is being called from an `attach` method. + * @returns {*} - The subform instance. */ createSubForm(fromAttach) { this.subFormReady = this.loadSubForm(fromAttach).then((form) => { @@ -485,6 +485,8 @@ export default class FormComponent extends Component { /** * Load the subform. + * @param {boolean} fromAttach - This function is being called from an `attach` method. + * @returns {Promise} - The promise that resolves when the subform is loaded. */ loadSubForm(fromAttach) { if (this.builderMode || this.isHidden() || (this.isSubFormLazyLoad() && !fromAttach)) { @@ -581,7 +583,7 @@ export default class FormComponent extends Component { /** * Determine if the subform should be submitted. - * @return {*|boolean} + * @returns {*|boolean} - TRUE if the subform should be submitted, FALSE if it should not. */ get shouldSubmit() { return this.subFormReady && (!this.component.hasOwnProperty('reference') || this.component.reference) && !this.isHidden(); @@ -589,8 +591,7 @@ export default class FormComponent extends Component { /** * Returns the data for the subform. - * - * @return {*} + * @returns {*} - the data for the subform. */ getSubFormData() { if (_.get(this.subForm, 'form.display') === 'pdf') { @@ -603,8 +604,7 @@ export default class FormComponent extends Component { /** * Submit the subform if configured to do so. - * - * @return {*} + * @returns {Promise} - The promise that resolves when the subform is submitted. */ submitSubForm() { // If we wish to submit the form on next page, then do that here. @@ -632,6 +632,8 @@ export default class FormComponent extends Component { /** * Submit the form before the next page is triggered. + * @param {Function} next - The function to trigger the next page. + * @returns {Promise} - The promise that resolves when the subform submission is complete (if necessary) and the next page is triggered. */ beforePage(next) { // Should not submit child forms if we are going to the previous page @@ -643,6 +645,7 @@ export default class FormComponent extends Component { /** * Submit the form before the whole form is triggered. + * @returns {Promise} - The promise that resolves when the subform submission is complete (if necessary) and the form is submitted. */ beforeSubmit() { const submission = this.dataValue; @@ -767,7 +770,7 @@ export default class FormComponent extends Component { /** * Determines if this form is a Nested Wizard * which means it should be a Wizard itself and should be a direct child of a Wizard's page - * @returns {boolean} + * @returns {boolean} - TRUE if this form is a Nested Wizard, FALSE otherwise */ get isNestedWizard() { return this.subForm?._form?.display === 'wizard' && this.parent?.parent?._form?.display === 'wizard'; diff --git a/src/components/hidden/Hidden.form.js b/src/components/hidden/Hidden.form.js index 1e11a9404b..552f4ba1eb 100644 --- a/src/components/hidden/Hidden.form.js +++ b/src/components/hidden/Hidden.form.js @@ -2,6 +2,11 @@ import Components from '../Components'; import HiddenEditDisplay from './editForm/Hidden.edit.display'; import HiddenEditData from './editForm/Hidden.edit.data'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return Components.baseEditForm([ { diff --git a/src/components/hidden/Hidden.js b/src/components/hidden/Hidden.js index 0f09c4adf5..23f954f4e5 100644 --- a/src/components/hidden/Hidden.js +++ b/src/components/hidden/Hidden.js @@ -39,8 +39,7 @@ export default class HiddenComponent extends Input { /** * Check if a component is eligible for multiple validation - * - * @return {boolean} + * @returns {boolean} - If the component is eligible for multiple validation. */ validateMultiple() { // Since "arrays" are able to be stored in hidden components, we need to turn off multiple validation. diff --git a/src/components/html/HTML.form.js b/src/components/html/HTML.form.js index 7f793d24f8..84e3707323 100644 --- a/src/components/html/HTML.form.js +++ b/src/components/html/HTML.form.js @@ -2,6 +2,11 @@ import Components from '../Components'; import HTMLEditDisplay from './editForm/HTML.edit.display'; import HTMLEditLogic from './editForm/HTML.edit.logic'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return Components.baseEditForm([ { diff --git a/src/components/number/Number.form.js b/src/components/number/Number.form.js index 0819732999..61b80d23d5 100644 --- a/src/components/number/Number.form.js +++ b/src/components/number/Number.form.js @@ -4,6 +4,11 @@ import NumberEditDisplay from './editForm/Number.edit.display'; import NumberEditData from './editForm/Number.edit.data'; import NumberEditValidation from './editForm/Number.edit.validation'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return textEditForm([ { diff --git a/src/components/number/Number.js b/src/components/number/Number.js index 2b11773a61..3d90c287fd 100644 --- a/src/components/number/Number.js +++ b/src/components/number/Number.js @@ -83,8 +83,7 @@ export default class NumberComponent extends Input { /** * Creates the number mask for normal numbers. - * - * @return {*} + * @returns {*} - The number mask. */ createNumberMask() { return createNumberMask({ diff --git a/src/components/panel/Panel.form.js b/src/components/panel/Panel.form.js index 3335332268..ed92335bfa 100644 --- a/src/components/panel/Panel.form.js +++ b/src/components/panel/Panel.form.js @@ -3,6 +3,11 @@ import nestedComponentForm from '../_classes/nested/NestedComponent.form'; import PanelEditDisplay from './editForm/Panel.edit.display'; import PanelEditConditional from './editForm/Panel.edit.conditional'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return nestedComponentForm([ { diff --git a/src/components/panel/Panel.js b/src/components/panel/Panel.js index 264232e9cd..f6b1761bd1 100644 --- a/src/components/panel/Panel.js +++ b/src/components/panel/Panel.js @@ -1,6 +1,5 @@ import NestedComponent from '../_classes/nested/NestedComponent'; import { isChildOf } from '../../utils/utils'; -import FormComponent from '../form/Form'; export default class PanelComponent extends NestedComponent { static schema(...extend) { diff --git a/src/components/password/Password.form.js b/src/components/password/Password.form.js index 6c4e9bd123..c57f94aa3f 100644 --- a/src/components/password/Password.form.js +++ b/src/components/password/Password.form.js @@ -4,6 +4,11 @@ import PasswordEditDisplay from './editForm/Password.edit.display'; import PasswordEditData from './editForm/Password.edit.data'; import PasswordEditValidation from './editForm/Password.edit.validation'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return textEditForm([ { diff --git a/src/components/phonenumber/PhoneNumber.form.js b/src/components/phonenumber/PhoneNumber.form.js index 5a34323540..a8b0ba6cf1 100644 --- a/src/components/phonenumber/PhoneNumber.form.js +++ b/src/components/phonenumber/PhoneNumber.form.js @@ -2,6 +2,11 @@ import textEditForm from '../textfield/TextField.form'; import PhoneNumberEditValidation from './editForm/PhoneNumber.edit.validation'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return textEditForm([ { diff --git a/src/components/radio/Radio.form.js b/src/components/radio/Radio.form.js index 165a41f278..44d0ec86c6 100644 --- a/src/components/radio/Radio.form.js +++ b/src/components/radio/Radio.form.js @@ -3,6 +3,11 @@ import RadioEditData from './editForm/Radio.edit.data'; import RadioEditDisplay from './editForm/Radio.edit.display'; import RadioEditValidation from './editForm/Radio.edit.validation'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return listComponentForm([ { diff --git a/src/components/radio/Radio.js b/src/components/radio/Radio.js index 34228bda79..73ca8f0912 100644 --- a/src/components/radio/Radio.js +++ b/src/components/radio/Radio.js @@ -413,10 +413,9 @@ export default class RadioComponent extends ListComponent { } /** - * Normalize values coming into updateValue. - * - * @param value - * @return {*} + * Normalize values coming into updateValue. For example, depending on the configuration, string value `"true"` will be normalized to boolean `true`. + * @param {*} value - The value to normalize + * @returns {*} - Returns the normalized value */ normalizeValue(value) { const dataType = this.component.dataType || 'auto'; diff --git a/src/components/recaptcha/ReCaptcha.form.js b/src/components/recaptcha/ReCaptcha.form.js index 6171a71043..116f7afc02 100644 --- a/src/components/recaptcha/ReCaptcha.form.js +++ b/src/components/recaptcha/ReCaptcha.form.js @@ -1,6 +1,10 @@ import Components from '../Components'; import ReCaptchaEditDisplay from './editForm/ReCaptcha.edit.display'; +/** + * The Edit Form function. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function() { return Components.baseEditForm([ { diff --git a/src/components/select/Select.form.js b/src/components/select/Select.form.js index 93e6d01cf6..7a223be7d0 100644 --- a/src/components/select/Select.form.js +++ b/src/components/select/Select.form.js @@ -3,6 +3,11 @@ import SelectEditData from './editForm/Select.edit.data'; import SelectEditDisplay from './editForm/Select.edit.display'; import SelectEditValidation from './editForm/Select.edit.validation'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return listComponentForm([ { diff --git a/src/components/select/Select.js b/src/components/select/Select.js index 26641a7edb..051484f585 100644 --- a/src/components/select/Select.js +++ b/src/components/select/Select.js @@ -331,9 +331,10 @@ export default class SelectComponent extends ListComponent { /** * Adds an option to the select dropdown. - * - * @param value - * @param label + * @param {*} value - The value of the new option. + * @param {string} label - The label of the new option. + * @param {object} [attrs] - Additional value attributes. Defaults to {}. + * @param {string} [id] - An id. Defaults to a random string. */ addOption(value, label, attrs = {}, id = getRandomComponentId()) { if (_.isNil(label)) return; @@ -695,6 +696,7 @@ export default class SelectComponent extends ListComponent { } /** * Get the request headers for this select dropdown. + * @returns {*} - Returns the request headers for this select dropdown. */ get requestHeaders() { // Create the headers object. @@ -1259,10 +1261,6 @@ export default class SelectComponent extends ListComponent { return super.visible; } - /** - * @param {*} value - * @param {Array} items - */ addCurrentChoices(values, items, keyValue) { if (!values) { return false; @@ -1440,10 +1438,9 @@ export default class SelectComponent extends ListComponent { } /** - * Normalize values coming into updateValue. - * - * @param value - * @return {*} + * Normalize values coming into updateValue. For example, depending on the configuration, string value `"true"` will be normalized to boolean `true`. + * @param {*} value - The value to normalize + * @returns {*} - Returns the normalized value */ normalizeValue(value) { if (this.component.multiple && Array.isArray(value)) { @@ -1663,7 +1660,8 @@ export default class SelectComponent extends ListComponent { /** * Performs required transformations on the initial value to use in selectOptions - * @param {*} value + * @param {*} value - The value to transform. + * @returns {*} - Returns the options value. */ getOptionValue(value) { return _.isObject(value) && this.isEntireObjectDisplay() @@ -1679,7 +1677,7 @@ export default class SelectComponent extends ListComponent { /** * If component has static values (values, json) or custom values, returns an array of them - * @returns {Array<*>|undefined} + * @returns {Array<*>|undefined} - Returns an array of the static or custom values. */ getOptionsValues() { let rawItems = []; @@ -1724,8 +1722,7 @@ export default class SelectComponent extends ListComponent { /** * Check if a component is eligible for multiple validation - * - * @return {boolean} + * @returns {boolean} - Returns FALSE for select components. */ validateMultiple() { // Select component will contain one input when flagged as multiple. @@ -1734,7 +1731,7 @@ export default class SelectComponent extends ListComponent { /** * Output this select dropdown as a string value. - * @return {*} + * @returns {*} */ isBooleanOrNumber(value) { diff --git a/src/components/selectboxes/SelectBoxes.form.js b/src/components/selectboxes/SelectBoxes.form.js index 7d7300fc56..296c0a1e5f 100644 --- a/src/components/selectboxes/SelectBoxes.form.js +++ b/src/components/selectboxes/SelectBoxes.form.js @@ -1,6 +1,11 @@ import radioEditForm from '../radio/Radio.form'; import SelectBoxesEditValidation from './editForm/SelectBoxes.edit.validation'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return radioEditForm([ { diff --git a/src/components/selectboxes/SelectBoxes.js b/src/components/selectboxes/SelectBoxes.js index cbb4583db9..7aa3b93514 100644 --- a/src/components/selectboxes/SelectBoxes.js +++ b/src/components/selectboxes/SelectBoxes.js @@ -97,9 +97,8 @@ export default class SelectBoxesComponent extends RadioComponent { /** * Only empty if the values are all false. - * - * @param value - * @return {boolean} + * @param {any} value - The value to check if empty. + * @returns {boolean} - If the value is empty. */ isEmpty(value = this.dataValue) { let empty = true; @@ -126,9 +125,8 @@ export default class SelectBoxesComponent extends RadioComponent { /** * Normalize values coming into updateValue. - * - * @param value - * @return {*} + * @param {any} value - The value to normalize. + * @returns {*} - The normalized value */ normalizeValue(value) { value = value || {}; @@ -164,9 +162,9 @@ export default class SelectBoxesComponent extends RadioComponent { /** * Set the value of this component. - * - * @param value - * @param flags + * @param {any} value - The value to set. + * @param {any} flags - Flags to apply to this update. + * @returns {boolean} - If the value has changed. */ setValue(value, flags = {}) { const changed = this.updateValue(value, flags); diff --git a/src/components/signature/Signature.form.js b/src/components/signature/Signature.form.js index d7db9e4fb8..4b66dd970b 100644 --- a/src/components/signature/Signature.form.js +++ b/src/components/signature/Signature.form.js @@ -3,6 +3,11 @@ import SignatureEditData from './editForm/Signature.edit.data'; import SignatureEditDisplay from './editForm/Signature.edit.display'; import SignatureEditValidation from './editForm/Signature.edit.validation'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return Components.baseEditForm([ { diff --git a/src/components/survey/Survey.form.js b/src/components/survey/Survey.form.js index 0db2c40aaf..6724e35739 100644 --- a/src/components/survey/Survey.form.js +++ b/src/components/survey/Survey.form.js @@ -3,6 +3,11 @@ import SurveyEditData from './editForm/Survey.edit.data'; import SurveyEditDisplay from './editForm/Survey.edit.display'; import SurveyEditValidation from './editForm/Survey.edit.validation'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return Components.baseEditForm([ { diff --git a/src/components/table/Table.form.js b/src/components/table/Table.form.js index a0e1155f6a..08dde4bd11 100644 --- a/src/components/table/Table.form.js +++ b/src/components/table/Table.form.js @@ -2,6 +2,11 @@ import nestedComponentForm from '../_classes/nested/NestedComponent.form'; import TableEditDisplay from './editForm/Table.edit.display'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return nestedComponentForm([ { diff --git a/src/components/tabs/Tabs.form.js b/src/components/tabs/Tabs.form.js index 2a02192ac0..87e842f4d2 100644 --- a/src/components/tabs/Tabs.form.js +++ b/src/components/tabs/Tabs.form.js @@ -2,6 +2,11 @@ import nestedComponentForm from '../_classes/nested/NestedComponent.form'; import TabsEditDisplay from './editForm/Tabs.edit.display'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return nestedComponentForm([ { diff --git a/src/components/tabs/Tabs.js b/src/components/tabs/Tabs.js index 865ae35205..1672e91896 100644 --- a/src/components/tabs/Tabs.js +++ b/src/components/tabs/Tabs.js @@ -131,8 +131,7 @@ export default class TabsComponent extends NestedComponent { /** * Set the current tab. - * - * @param index + * @param {number} index - The index of the tab to set. */ setTab(index) { if (!this.tabs || !this.tabs[index] || !this.refs[this.tabKey] || !this.refs[this.tabKey][index]) { diff --git a/src/components/tags/Tags.form.js b/src/components/tags/Tags.form.js index 40fb75a39f..bf70a95b10 100644 --- a/src/components/tags/Tags.form.js +++ b/src/components/tags/Tags.form.js @@ -2,6 +2,11 @@ import Components from '../Components'; import TagsEditData from './editForm/Tags.edit.data'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return Components.baseEditForm([ { diff --git a/src/components/textarea/TextArea.form.js b/src/components/textarea/TextArea.form.js index b8cf874c10..de42a3eb1e 100644 --- a/src/components/textarea/TextArea.form.js +++ b/src/components/textarea/TextArea.form.js @@ -2,6 +2,11 @@ import textEditForm from '../textfield/TextField.form'; import TextAreaEditDisplay from './editForm/TextArea.edit.display'; import TextAreaEditValidation from './editForm/TextArea.edit.validation'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return textEditForm([ { diff --git a/src/components/textarea/TextArea.js b/src/components/textarea/TextArea.js index cb64c9d41b..596eb2fed5 100644 --- a/src/components/textarea/TextArea.js +++ b/src/components/textarea/TextArea.js @@ -89,8 +89,8 @@ export default class TextAreaComponent extends TextFieldComponent { /** * Updates the editor value. - * - * @param newValue + * @param {number} index - The index of the editor. + * @param {any} newValue - The new editor value. */ updateEditorValue(index, newValue) { newValue = this.getConvertedValue(this.trimBlanks(newValue)); diff --git a/src/components/textfield/TextField.form.js b/src/components/textfield/TextField.form.js index 50c8c4738e..2c752e7601 100644 --- a/src/components/textfield/TextField.form.js +++ b/src/components/textfield/TextField.form.js @@ -4,6 +4,11 @@ import TextFieldEditData from './editForm/TextField.edit.data'; import TextFieldEditDisplay from './editForm/TextField.edit.display'; import TextFieldEditValidation from './editForm/TextField.edit.validation'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return Components.baseEditForm([ { diff --git a/src/components/textfield/TextField.js b/src/components/textfield/TextField.js index 94c22923c6..78b782c177 100644 --- a/src/components/textfield/TextField.js +++ b/src/components/textfield/TextField.js @@ -110,11 +110,10 @@ export default class TextFieldComponent extends Input { } /** - * Returns the mask value object. - * - * @param value - * @param flags - * @return {*} + * Returns the mask value object (mutates value!). + * @param {any} [value] - The value to convert to a mask value. + * @param {any} [flags] - The flags to use when converting to a mask value. + * @returns {*} - The value as a mask value. */ maskValue(value, flags = {}) { // Convert it into the correct format. @@ -136,10 +135,9 @@ export default class TextFieldComponent extends Input { /** * Normalize the value set in the data object. - * - * @param value - * @param flags - * @return {*} + * @param {any} value - The value to normalize. + * @param {any} flags - The flags to use when normalizing the value. + * @returns {*} - Returns the normalized value. */ normalizeValue(value, flags = {}) { if (!this.isMultipleMasksField) { @@ -153,10 +151,10 @@ export default class TextFieldComponent extends Input { /** * Sets the value at this index. - * - * @param index - * @param value - * @param flags + * @param {number} index - The index to set the value at. + * @param {any} value - The value to set. + * @param {any} [flags] - The flags to use when setting the value. + * @returns {void} */ setValueAt(index, value, flags = {}) { if (!this.isMultipleMasksField) { @@ -191,9 +189,8 @@ export default class TextFieldComponent extends Input { /** * Returns the value at this index. - * - * @param index - * @return {*} + * @param {number} index - The index to get the value from. + * @returns {*} - The value at the index. */ getValueAt(index) { if (!this.isMultipleMasksField) { diff --git a/src/components/time/Time.form.js b/src/components/time/Time.form.js index b21d70c3b5..8de114a35f 100644 --- a/src/components/time/Time.form.js +++ b/src/components/time/Time.form.js @@ -3,6 +3,11 @@ import baseEditForm from '../_classes/component/Component.form'; import TimeEditData from './editForm/Time.edit.data'; import TimeEditDisplay from './editForm/Time.edit.display'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return baseEditForm([ { diff --git a/src/components/unknown/Unknown.form.js b/src/components/unknown/Unknown.form.js index d111ace1c4..400082577e 100644 --- a/src/components/unknown/Unknown.form.js +++ b/src/components/unknown/Unknown.form.js @@ -1,4 +1,9 @@ import UnknownEditDisplay from './editForm/Unknown.edit.display'; + +/** + * Unknown Component schema. + * @returns {object} - The Unknown Component edit form. + */ export default function() { return { components: [ diff --git a/src/components/url/Url.form.js b/src/components/url/Url.form.js index 4b772ba6a9..451538ebe1 100644 --- a/src/components/url/Url.form.js +++ b/src/components/url/Url.form.js @@ -4,6 +4,11 @@ import UrlEditDisplay from './editForm/Url.edit.display'; import UrlEditData from './editForm/Url.edit.data'; import UrlEditValidation from './editForm/Url.edit.validation'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return textEditForm([ { diff --git a/src/components/well/Well.form.js b/src/components/well/Well.form.js index 1c7f876482..e5924360ff 100644 --- a/src/components/well/Well.form.js +++ b/src/components/well/Well.form.js @@ -2,6 +2,11 @@ import nestedComponentForm from '../_classes/nested/NestedComponent.form'; import WellEditDisplay from './editForm/Well.edit.display'; +/** + * The Edit Form function. + * @param {...any} extend - The components that extend the edit form. + * @returns {import('@formio/core').Component[]} - The edit form components. + */ export default function(...extend) { return nestedComponentForm([ { diff --git a/src/formio.form.js b/src/formio.form.js index b533354653..787227c51f 100644 --- a/src/formio.form.js +++ b/src/formio.form.js @@ -40,8 +40,10 @@ Formio.Components.setComponents(AllComponents); /** * Register a module - * @param {*} plugin - * @returns + * @param {any} mod - The module object to register. This can also be a function which accepts Formio as an argument. + * @param {Function|null} [defaultFn] - The default function to call if the module does not have a known key. + * @param {any} options - Options for the module. + * @returns {void} */ export function registerModule(mod, defaultFn = null, options = {}) { if (typeof mod === 'function') { @@ -103,6 +105,10 @@ export function registerModule(mod, defaultFn = null, options = {}) { } } +/** + * @param {Function|null} defaultFn - The default function to call if the module does not have a known key. + * @returns {void} + */ export function useModule(defaultFn = null) { return (plugins, options = {}) => { plugins = _.isArray(plugins) ? plugins : [plugins]; diff --git a/src/providers/Providers.js b/src/providers/Providers.js index 6e7d15c384..1fca4aa910 100644 --- a/src/providers/Providers.js +++ b/src/providers/Providers.js @@ -4,6 +4,14 @@ import address from './address'; import auth from './auth'; import storage from './storage'; + +/** + * @class Providers + * @classdesc Represents a collection of providers. + */ +/** + * Represents a collection of providers. + */ export default class Providers { static providers = { address, @@ -11,21 +19,40 @@ export default class Providers { storage, }; + /** + * Adds a provider to the collection. + * @param {string} type - The type of the provider. + * @param {string} name - The name of the provider. + * @param {Provider} provider - The provider object. + */ static addProvider(type, name, provider) { Providers.providers[type] = Providers.providers[type] || {}; Providers.providers[type][name] = provider; } - + /** + * Adds multiple providers to the collection. + * @param {string} type - The type of the providers. + * @param {{ [key: string]: Provider }} providers - The collection of providers. + */ static addProviders(type, providers) { Providers.providers[type] = _.merge(Providers.providers[type], providers); } - + /** + * Retrives a provider a provider from the collection. + * @param {string} type - The type of the provider. + * @param {string} name - The name of the provider. + * @returns {Provider | void} The provider object. + */ static getProvider(type, name) { if (Providers.providers[type] && Providers.providers[type][name]) { return Providers.providers[type][name]; } } - + /** + * Retrives all providers of a given type. + * @param {string} type - The type of the providers. + * @returns {Provider[] | void} The collection of providers. + */ static getProviders(type) { if (Providers.providers[type]) { return Providers.providers[type]; diff --git a/src/providers/address/AddressProvider.js b/src/providers/address/AddressProvider.js index 442e71a022..9e6988fa30 100644 --- a/src/providers/address/AddressProvider.js +++ b/src/providers/address/AddressProvider.js @@ -2,68 +2,162 @@ import _ from 'lodash'; import { Formio } from '../../Formio'; +/** + * @typedef {object} RequestOptions + * @property {object} params - The request parameters. + * @property {boolean} noToken - Whether to include a token in the request. + */ + +/** + * @typedef {object} Address + * @property {string} street - The street address. + * @property {string} city - The city. + * @property {string} state - The state. + * @property {string} country - The country. + * @property {string} postalCode - The postal code. + */ + +/** + * @class AddressProvider + * @classdesc Represents an address provider. + */ export class AddressProvider { + /** + * @static + * @type {string} + * @description The name of the address provider. + */ static get name() { + return 'address'; } + /** + * @static + * @type {string} + * @description The display name of the address provider. + */ static get displayName() { + return 'Address'; } + /** + * @class + * @param {object} options - The options for the address provider. + */ constructor(options = {}) { + this.beforeMergeOptions(options); this.options = _.merge({}, this.defaultOptions, options); } + /** + * @private + * @description Executes before merging the options. + */ beforeMergeOptions() { + return; } + /** + * @private + * @type {object} + * @description The default options for the address provider. + */ + get defaultOptions() { return {}; } + /** + * @private + * @type {string} + * @description The query property name. + */ get queryProperty() { return 'query'; } + + /** + * @private + * @type {string|null} + * @description The response property name. + */ get responseProperty() { return null; } + + /** + * @private + * @type {string|null} + * @description The display value property name. + */ get displayValueProperty() { return null; } + /** + * @private + * @param {object} params - The parameters to serialize. + * @returns {string} The serialized parameters. + */ serialize(params) { return _.toPairs(params).map(([key, value]) => `${encodeURIComponent(key)}=${encodeURIComponent(value)}`).join('&'); } + /** + * @private + * @param {object} options - The request options. + * @returns {RequestOptions} The merged request options. + */ getRequestOptions(options = {}) { return _.merge({}, this.options, options); } - // eslint-disable-next-line no-unused-vars - getRequestUrl(options = {}) { + /** + * @private + * @param {object} _options - The request options. + * @throws {Error} Throws an error if the method is not implemented. + */ + getRequestUrl(_options = {}) { throw new Error('Method AddressProvider#getRequestUrl(options) is abstract.'); } + /** + * @private + * @param {object} options - The request options. + * @returns {Promise} A promise that resolves with the request result. + */ makeRequest(options = {}) { return Formio.makeStaticRequest(this.getRequestUrl(options), 'GET', null, { noToken: true, }); } + /** + * @public + * @description The search parameters for the request. + * @param {string} query - The search query. + * @param {object} options - The search options. + * @returns {Promise} A promise that resolves with the search results. + */ search(query, options = {}) { const requestOptions = this.getRequestOptions(options); const params = requestOptions.params = requestOptions.params || {}; params[this.queryProperty] = query; - return this.makeRequest(requestOptions) .then((result) => this.responseProperty ? _.get(result, this.responseProperty, []) : result); } + /** + * @public + * @param {Address} address - The address object. + * @returns {string} The display value of the address. + */ getDisplayValue(address) { return this.displayValueProperty ? _.get(address, this.displayValueProperty, '') : String(address); } diff --git a/src/providers/address/AzureAddressProvider.js b/src/providers/address/AzureAddressProvider.js index a5edb697df..86d83657c4 100644 --- a/src/providers/address/AzureAddressProvider.js +++ b/src/providers/address/AzureAddressProvider.js @@ -1,14 +1,38 @@ import { AddressProvider } from './AddressProvider'; + +/** + * @typedef {object} AzureAddressProviderOptionsParams + * @property {string} 'api-version' - The version of the Azure Maps API. + * @property {string} typeahead - Whether to enable typeahead in the search. + * @typedef {object} AzureAddressProviderOptions + * @property {AzureAddressProviderOptionsParams} params - The parameters for the Azure Maps API request. + */ + +/** + * @class + * @augments AddressProvider + * @classdesc Represents an Azure Maps address provider. + */ export class AzureAddressProvider extends AddressProvider { + /** + * Gets the name of the address provider. + * @type {string} + */ static get name() { return 'azure'; } - + /** + * Gets the display name of the address provider. + * @type {string} + */ static get displayName() { return 'Azure Maps'; } - + /** + * Gets the default options for the address provider. + * @returns {{ params: { 'api-version': string, typeahead: string } }} The default options. + */ get defaultOptions() { return { params: { @@ -17,15 +41,26 @@ export class AzureAddressProvider extends AddressProvider { }, }; } - + /** + * Gets the response property for the address provider. + * @type {string} + */ get responseProperty() { return 'results'; } - + /** + * Gets the display value property for the address provider. + * @type {string} + */ get displayValueProperty() { return 'address.freeformAddress'; } + /** + * Gets the request URL for the address provider. + * @param {{params: any}} options - The request options. + * @returns {string} The request URL. + */ getRequestUrl(options = {}) { const { params } = options; diff --git a/src/providers/address/CustomAddressProvider.js b/src/providers/address/CustomAddressProvider.js index 49b3d7d87f..da685dc93b 100644 --- a/src/providers/address/CustomAddressProvider.js +++ b/src/providers/address/CustomAddressProvider.js @@ -1,26 +1,60 @@ import { AddressProvider } from './AddressProvider'; +/** + * CustomAddressProvider class extends the AddressProvider class and provides custom functionality for address handling. + * @augments AddressProvider + */ export class CustomAddressProvider extends AddressProvider { + /** + * Returns the name of the custom address provider. + * @type {string} + */ static get name() { return 'custom'; } + /** + * Returns the display name of the custom address provider. + * @type {string} + */ static get displayName() { return 'Custom'; } + /** + * Returns the query property of the custom address provider. + * If not provided, falls back to the query property of the parent class. + * @type {string} + */ get queryProperty() { return this.options.queryProperty || super.queryProperty; } + /** + * Returns the response property of the custom address provider. + * If not provided, falls back to the response property of the parent class. + * @type {string} + */ get responseProperty() { return this.options.responseProperty || super.responseProperty; } + /** + * Returns the display value property of the custom address provider. + * If not provided, falls back to the display value property of the parent class. + * @type {string} + */ get displayValueProperty() { return this.options.displayValueProperty || super.displayValueProperty; } + /** + * Returns the request URL for the custom address provider. + * @param {object} options - The options for the request. + * @param {object} options.params - The parameters for the request. + * @param {string} options.url - The URL for the request. + * @returns {string} The request URL. + */ getRequestUrl(options = {}) { const { params, url } = options; diff --git a/src/providers/address/GoogleAddressProvider.js b/src/providers/address/GoogleAddressProvider.js index 38ec86f331..7c34a29e24 100644 --- a/src/providers/address/GoogleAddressProvider.js +++ b/src/providers/address/GoogleAddressProvider.js @@ -2,89 +2,172 @@ import { Formio } from '../../Formio'; import _ from 'lodash'; import { AddressProvider } from './AddressProvider'; - +/** + * @typedef {object} AutocompleteOptions + * @property {string[]} fields - The fields to include in the autocomplete response. + * @property {object} componentRestrictions - The component restrictions for the autocomplete response. + * @property {string[]} componentRestrictions.country - The country codes to restrict the autocomplete response to. + */ + +/** + * @typedef {object} ProviderOptions + * @property {string} region - The region to restrict the autocomplete response to. + * @property {string} key - The API key for Google Maps. + * @property {AutocompleteOptions} autocompleteOptions - The options for the autocomplete functionality. + */ + +/** + * @typedef {object} Place + * @property {object} address_components - The address components of the place. + * @property {string} formatted_address - The formatted address of the place. + * @property {object} geometry - The geometry information of the place. + * @property {string} place_id - The place ID of the place. + * @property {object} plus_code - The plus code of the place. + * @property {string[]} types - The types of the place. + * @property {string} formattedPlace - The formatted place value. + */ + +/** + * @class GoogleAddressProvider + * @augments AddressProvider + */ export class GoogleAddressProvider extends AddressProvider { + /** + * @returns {string} The name of the provider. + */ + static get name() { return 'google'; } + + /** + * @returns {string} The display name of the provider. + */ + static get displayName() { + return 'Google Maps'; } + /** + + * @param {ProviderOptions} options - The options for the provider. + */ + constructor(options = {}) { super(options); this.setAutocompleteOptions(); - let src = 'https://maps.googleapis.com/maps/api/js?v=quarterly&libraries=places&callback=googleMapsCallback'; - if (options.params?.key) { src += `&key=${options.params.key}`; } - Formio.requireLibrary(this.getLibraryName(), 'google.maps.places', src); } + + /** + * get display value property + * @returns {string} The property to use for display value. + */ + get displayValueProperty() { return 'formattedPlace'; } + + /** + * @returns {string} The alternative property to use for display value. + */ + get alternativeDisplayValueProperty() { return 'formatted_address'; + } + /** + * @param {AutocompleteOptions} options - The autocomplete options. + */ set autocompleteOptions(options) { this._autocompleteOptions = options; } + + /** + * @returns {AutocompleteOptions} The autocomplete options. + */ get autocompleteOptions() { + return this._autocompleteOptions; } + /** + * Sets the autocomplete options based on the provider options. + + */ setAutocompleteOptions() { let options = _.get(this.options, 'params.autocompleteOptions', {}); if (!_.isObject(options)) { options = {}; } - this.addRequiredProviderOptions(options); + this.autocompleteOptions = options; } + /** + + * Converts the region to autocomplete option if it exists. + * @param {ProviderOptions} options - The provider options. + */ + beforeMergeOptions(options) { // providing support of old Google Provider option this.convertRegionToAutocompleteOption(options); } + + /** + * @returns {string} The name of the library. + */ getLibraryName() { return 'googleMaps'; } + /** + * Converts the region to autocomplete option. + * @param {ProviderOptions} options - The provider options. + */ convertRegionToAutocompleteOption(options) { + const providerOptions = options; let region = _.get(providerOptions, 'params.region', ''); - if (region && !_.has(options, 'params.autocompleteOptions')) { region = region.toUpperCase().trim(); // providing compatibility with ISO 3166-1 Alpha-2 county codes (for checking compatibility https://en.wikipedia.org/wiki/List_of_ISO_3166_country_codes) const countryCodes = { 'UK': 'GB' }; - if (countryCodes[region]) { region = countryCodes[region]; } - _.set(providerOptions, 'params.autocompleteOptions.componentRestrictions.country', [region]); } } + /** + * @returns {string[]} The required address properties. + */ getRequiredAddressProperties() { return ['address_components', 'formatted_address','geometry','place_id', 'plus_code', 'types']; } + /** + * Adds the required provider options to the options. + * @param {AutocompleteOptions} options - The autocomplete options. + */ addRequiredProviderOptions(options) { - const addressProperties = this.getRequiredAddressProperties(); + const addressProperties = this.getRequiredAddressProperties(); if (_.isArray(options.fields) && options.fields.length > 0 ) { options.fields.forEach(optionalField => { if (!addressProperties.some(addressProp => optionalField === addressProp)) { diff --git a/src/providers/address/NominatimAddressProvider.js b/src/providers/address/NominatimAddressProvider.js index 04a391fd56..13c730b6bf 100644 --- a/src/providers/address/NominatimAddressProvider.js +++ b/src/providers/address/NominatimAddressProvider.js @@ -1,14 +1,33 @@ import { AddressProvider } from './AddressProvider'; +/** + * @typedef {object} NominatimAddressProviderOptionsParams + * @property {{ addressdetails: string, format: string } } params - The parameters for the Nominatim API request. + */ +/** + * Represents an Nominatim address provider. + * {extends AddressProvider} + */ + export class NominatimAddressProvider extends AddressProvider { + /** + * Gets the name of the address provider. + * @type {string} + */ static get name() { return 'nominatim'; } - + /** + * Gets the display name of the address provider. + * @type {string} + */ static get displayName() { return 'OpenStreetMap Nominatim'; } - + /** + * Gets the default options for the address provider. + * @returns {NominatimAddressProviderOptionsParams} The default options. + */ get defaultOptions() { return { params: { @@ -17,15 +36,25 @@ export class NominatimAddressProvider extends AddressProvider { }, }; } - + /** + * Gets the response property for the address provider. + * @type {string} + */ get queryProperty() { return 'q'; } - + /** + * Gets the display value property for the address provider. + * @returns {string} The property to use for display value. + */ get displayValueProperty() { return 'display_name'; } - + /** + * Generates the request URL for the address provider with options. + * @param {NominatimAddressProviderOptionsParams} options - The request options. + * @returns {string} The formatted Url. + */ getRequestUrl(options = {}) { const { params } = options; diff --git a/src/providers/processor/fileProcessor.js b/src/providers/processor/fileProcessor.js index 869f73151a..23adcc1450 100644 --- a/src/providers/processor/fileProcessor.js +++ b/src/providers/processor/fileProcessor.js @@ -1,3 +1,9 @@ +/** + * Creates a file processor function. + * @param {Formio} formio - The Formio instance. + * @param {object} config - The configuration object. + * @returns {function(File, object): Promise} A function that takes a file and options, and returns a Promise that resolves with the processed file. + */ const fileProcessor = (formio, config) => (file, options) => new Promise((resolve, reject) => { const xhr = new XMLHttpRequest(); diff --git a/src/providers/storage/azure.js b/src/providers/storage/azure.js index 46fd5fbfb7..5476fb18a6 100644 --- a/src/providers/storage/azure.js +++ b/src/providers/storage/azure.js @@ -1,5 +1,13 @@ + import XHR from './xhr'; + +/** + * Azure File Services provider for file storage. + * @param {object} formio formio instance + * @returns {import('./typedefs').FileProvider} The FileProvider interface defined in index.js. + */ function azure(formio) { + return { uploadFile(file, fileName, dir, progressCallback, url, options, fileKey, groupPermissions, groupId, abortCallback) { return XHR.upload(formio, 'azure', (xhr, response) => { @@ -30,4 +38,7 @@ function azure(formio) { } azure.title = 'Azure File Services'; + + + export default azure; diff --git a/src/providers/storage/base64.js b/src/providers/storage/base64.js index c5fc7ab950..8935173e87 100644 --- a/src/providers/storage/base64.js +++ b/src/providers/storage/base64.js @@ -1,3 +1,7 @@ +/** + * base64 File Services provider for file storage. + * @returns {import('./typedefs').FileProvider} The FileProvider interface defined in index.js. + */ function base64() { return { title: 'Base64', diff --git a/src/providers/storage/dropbox.js b/src/providers/storage/dropbox.js index b1229fd674..2d97cb819d 100644 --- a/src/providers/storage/dropbox.js +++ b/src/providers/storage/dropbox.js @@ -1,4 +1,9 @@ import { setXhrHeaders } from './xhr'; +/** + * Dropbox provider for file storage. + * @param {object} formio formio instance + * @returns {import('./typedefs').FileProvider} The FileProvider interface defined in index.js. + */ function dropbox(formio) { return { uploadFile(file, fileName, dir, progressCallback, url, options, fileKey, groupPermissions, groupId, abortCallback) { @@ -62,6 +67,5 @@ function dropbox(formio) { } }; } - dropbox.title = 'Dropbox'; export default dropbox; diff --git a/src/providers/storage/googleDrive.js b/src/providers/storage/googleDrive.js index 655d01b5cd..b97a46a8c8 100644 --- a/src/providers/storage/googleDrive.js +++ b/src/providers/storage/googleDrive.js @@ -1,4 +1,11 @@ import { setXhrHeaders } from './xhr'; + +/** + * + * Google Drive provider for file storage. + * @param {object} formio - formio instance + * @returns {import('./typedefs').FileProvider} The FileProvider interface defined in index.js. + */ function googledrive(formio) { return { uploadFile(file, fileName, dir, progressCallback, url, options, fileKey, groupPermissions, groupId, abortCallback) { diff --git a/src/providers/storage/index.js b/src/providers/storage/index.js index 47ce885382..ace6103ab4 100644 --- a/src/providers/storage/index.js +++ b/src/providers/storage/index.js @@ -5,6 +5,8 @@ import url from './url'; import indexeddb from './indexeddb'; import googledrive from './googleDrive'; + + export default { base64, s3, diff --git a/src/providers/storage/indexeddb.js b/src/providers/storage/indexeddb.js index 0fbf206799..21c0fc6aa0 100644 --- a/src/providers/storage/indexeddb.js +++ b/src/providers/storage/indexeddb.js @@ -1,4 +1,8 @@ import { v4 as uuidv4 } from 'uuid'; +/** + * indexedDb provider for file storage. + * @returns {import('./typedefs').FileProvider} The FileProvider interface defined in index.js. + */ function indexeddb() { return { title: 'indexedDB', diff --git a/src/providers/storage/s3.js b/src/providers/storage/s3.js index 5afc8cc7da..c50e62c9a1 100644 --- a/src/providers/storage/s3.js +++ b/src/providers/storage/s3.js @@ -7,6 +7,11 @@ const loadAbortControllerPolyfill = async() => { } }; +/** + * S3 File Services provider for file storage. + * @param {object} formio formio instance + * @returns {import('./typedefs').FileProvider} The FileProvider interface defined in index.js. + */ function s3(formio) { return { async uploadFile(file, fileName, dir, progressCallback, url, options, fileKey, groupPermissions, groupId, abortCallback, multipartOptions) { diff --git a/src/providers/storage/url.js b/src/providers/storage/url.js index 7722e21b66..c65803e90c 100644 --- a/src/providers/storage/url.js +++ b/src/providers/storage/url.js @@ -1,4 +1,14 @@ +/** + * + * @param {object} formio - formio instance + * @returns {import('./typedefs').FileProvider} The FileProvider interface defined in index.js. + */ function url(formio) { + /** + * + * @param {object} options - options to set on the xhr + * @param {object} xhr - the xhr object + */ function setOptions(options, xhr) { const parsedOptions = typeof options === 'string' ? JSON.parse(options) : options; for (const prop in parsedOptions) { diff --git a/src/providers/storage/util.js b/src/providers/storage/util.js index f84101648f..53665773b7 100644 --- a/src/providers/storage/util.js +++ b/src/providers/storage/util.js @@ -1,3 +1,23 @@ +/** + * @typedef {any[]} Args + */ + +/** + * Function to be retried + * @callback RetryFunction + * @param {...Args} args + * @returns {Promise} + */ + +/** + * Executes a function with retries in case of failure. + * @param {RetryFunction} fn - The function to be executed. + * @param {Args} args - The arguments to be passed to the function. + * @param {number} [retries] - The number of retries in case of failure. + * @param {string} [err] - The error message to be thrown after all retries have failed. + * @returns {Promise} The result of the function execution. + * @throws {Error} When all retries have failed. + */ export async function withRetries(fn, args, retries = 3, err = null) { if (!retries) { throw new Error(err); diff --git a/src/utils/builder.js b/src/utils/builder.js index 0412628032..e983777414 100644 --- a/src/utils/builder.js +++ b/src/utils/builder.js @@ -3,11 +3,9 @@ import { eachComponent, uniqueKey } from './utils'; export default { /** * Appends a number to a component.key to keep it unique - * - * @param {Object} form - * The components parent form. - * @param {Object} component - * The component to uniquify + * @param {import('@formio/core').Component[]} container - The container of components to uniquify against + * @param {import('@formio/core').Component} component - The Component to uniqify. + * @returns {boolean} - If the component was changed. */ uniquify(container, component) { let changed = false; @@ -42,6 +40,9 @@ export default { return changed; }, + /** + * Additional shortcuts for the builder. + */ additionalShortcuts: { button: [ 'Enter', @@ -49,6 +50,10 @@ export default { ] }, + /** + * Returns the alpha character shortcuts. + * @returns {string[]} - An array of shortcuts of alpha characters. + */ getAlphaShortcuts() { return _.range('A'.charCodeAt(), 'Z'.charCodeAt() + 1).map((charCode) => String.fromCharCode(charCode)); }, diff --git a/src/utils/calendarUtils.js b/src/utils/calendarUtils.js index e3969a3e67..ff33374646 100644 --- a/src/utils/calendarUtils.js +++ b/src/utils/calendarUtils.js @@ -14,12 +14,11 @@ export const CALENDAR_ERROR_MESSAGES = { /** * Builds the response for checkInvalidDate. - * - * @param {String} message + * @param {string} message * The message for response. - * @param {Boolean} result + * @param {boolean} result * The boolean flag for response. - * * @return {{message: string, result: boolean}} + * @returns {{message: string, result: boolean}} - The response object. */ function buildResponse(message, result) { return { @@ -30,16 +29,15 @@ function buildResponse(message, result) { /** * Checks the value for a min date and max date. - * * @param {moment} value * The value to check. - * @param {[String]} format + * @param {[string]} format * A moment formats. * @param {Date} maxDate * The max date. * @param {Date} minDate * The min date. - * * @return {{message: string, result: boolean}} + * @returns {{message: string, result: boolean}} - The response object. */ export function lessOrGreater(value, format, maxDate, minDate) { let message = ''; @@ -71,16 +69,11 @@ export function lessOrGreater(value, format, maxDate, minDate) { /** * Checks the entered date for validity. - * - * @param {String} value - * The value to check. - * @param {[String]} format - * A moment formats. - * @param {Date} maxDate - * The max date. - * @param {Date} minDate - * The min date. - * * @return {{message: string, result: boolean}} + * @param {string} value - The value to check. + * @param {[string]} format - A moment formats. + * @param {Date} minDate - The minimum date. + * @param {Date} maxDate - The maximum date. + * @returns {{message: string, result: boolean}} - The response object. */ export function checkInvalidDate(value, format, minDate, maxDate) { const date = moment(value, format, true); diff --git a/src/utils/formUtils.js b/src/utils/formUtils.js index 05db606af2..30d6d1ba41 100644 --- a/src/utils/formUtils.js +++ b/src/utils/formUtils.js @@ -1,621 +1,91 @@ -import get from 'lodash/get'; -import set from 'lodash/set'; -import has from 'lodash/has'; -import clone from 'lodash/clone'; -import forOwn from 'lodash/forOwn'; -import isString from 'lodash/isString'; -import isNaN from 'lodash/isNaN'; -import isNil from 'lodash/isNil'; -import isPlainObject from 'lodash/isPlainObject'; -import round from 'lodash/round'; -import chunk from 'lodash/chunk'; -import pad from 'lodash/pad'; -import { compare, applyPatch } from 'fast-json-patch'; -import _ from 'lodash'; -import { fastCloneDeep } from './utils'; - -/** - * Determine if a component is a layout component or not. - * - * @param {Object} component - * The component to check. - * - * @returns {Boolean} - * Whether or not the component is a layout component. - */ -export function isLayoutComponent(component) { - return Boolean( - (component.columns && Array.isArray(component.columns)) || - (component.rows && Array.isArray(component.rows)) || - (component.components && Array.isArray(component.components)) - ); -} - -/** - * Iterate through each component within a form. - * - * @param {Object} components - * The components to iterate. - * @param {Function} fn - * The iteration function to invoke for each component. - * @param {Boolean} includeAll - * Whether or not to include layout components. - * @param {String} path - * The current data path of the element. Example: data.user.firstName - * @param {Object} parent - * The parent object. - */ -export function eachComponent(components, fn, includeAll, path, parent, inRecursion) { - if (!components) return; - path = path || ''; - if (inRecursion) { - if (components.noRecurse) { - delete components.noRecurse; - return; - } - components.noRecurse = true; - } - components.forEach((component) => { - if (!component) { - return; - } - const hasColumns = component.columns && Array.isArray(component.columns); - const hasRows = component.rows && Array.isArray(component.rows); - const hasComps = component.components && Array.isArray(component.components); - let noRecurse = false; - const newPath = component.key ? (path ? (`${path}.${component.key}`) : component.key) : ''; - - // Keep track of parent references. - if (parent) { - // Ensure we don't create infinite JSON structures. - component.parent = clone(parent); - delete component.parent.components; - delete component.parent.componentMap; - delete component.parent.columns; - delete component.parent.rows; - } - - // there's no need to add other layout components here because we expect that those would either have columns, rows or components - const layoutTypes = ['htmlelement', 'content']; - const isLayoutComponent = hasColumns || hasRows || (hasComps && !component.input) || layoutTypes.indexOf(component.type) > -1; - if (includeAll || component.tree || !isLayoutComponent) { - noRecurse = fn(component, newPath, components); - } - - const subPath = () => { - if ( - component.key && - !['panel', 'table', 'well', 'columns', 'fieldset', 'tabs', 'form'].includes(component.type) && - ( - ['datagrid', 'container', 'editgrid', 'address', 'dynamicWizard', 'datatable', 'tagpad'].includes(component.type) || - component.tree - ) - ) { - return newPath; - } - else if ( - component.key && - component.type === 'form' - ) { - return `${newPath}.data`; - } - return path; - }; - - if (!noRecurse) { - if (hasColumns) { - component.columns.forEach((column) => - eachComponent(column.components, fn, includeAll, subPath(), parent ? component : null), true); - } - - else if (hasRows) { - component.rows.forEach((row) => { - if (Array.isArray(row)) { - row.forEach((column) => - eachComponent(column.components, fn, includeAll, subPath(), parent ? component : null), true); - } - }); - } - - else if (hasComps) { - eachComponent(component.components, fn, includeAll, subPath(), parent ? component : null, true); - } - } - }); - if (components.noRecurse) { - delete components.noRecurse; - } -} - -/** - * Matches if a component matches the query. - * - * @param component - * @param query - * @return {boolean} - */ -export function matchComponent(component, query) { - if (isString(query)) { - return (component.key === query) || (component.path === query); - } - else { - let matches = false; - forOwn(query, (value, key) => { - matches = (get(component, key) === value); - if (!matches) { - return false; - } - }); - return matches; - } -} - -/** - * Get a component by its key - * - * @param {Object} components - * The components to iterate. - * @param {String|Object} key - * The key of the component to get, or a query of the component to search. - * - * @returns {Object} - * The component that matches the given key, or undefined if not found. - */ -export function getComponent(components, key, includeAll) { - let result; - eachComponent(components, (component, path) => { - if ((path === key) || (component.path === key)) { - result = component; - return true; - } - }, includeAll); - return result; -} - -/** - * Finds a component provided a query of properties of that component. - * - * @param components - * @param query - * @return {*} - */ -export function searchComponents(components, query) { - const results = []; - eachComponent(components, (component) => { - if (matchComponent(component, query)) { - results.push(component); - } - }, true); - return results; -} +import { Utils } from '@formio/core'; +const { + flattenComponents, + guid, + uniqueName, + MODEL_TYPES, + getModelType, + getComponentAbsolutePath, + getComponentPath, + isComponentModelType, + isComponentNestedDataType, + componentPath, + componentChildPath, + eachComponentDataAsync, + eachComponentData, + getComponentKey, + getContextualRowPath, + getContextualRowData, + componentInfo, + eachComponent, + eachComponentAsync, + getComponentData, + getComponentActualValue, + isLayoutComponent, + matchComponent, + getComponent, + searchComponents, + removeComponent, + hasCondition, + parseFloatExt, + formatAsCurrency, + escapeRegExCharacters, + getValue, + getStrings, + generateFormChange, + applyFormChanges, + findComponent, + getEmptyValue, + isComponentDataEmpty +} = Utils; /** * Deprecated version of findComponents. Renamed to searchComponents. - * - * @param components - * @param query - * @returns {*} + * @param {import('@formio/core').Component[]} components - The components to find components within. + * @param {object} query - The query to use when searching for the components. + * @returns {import('@formio/core').Component[]} - The result of the component that is found. */ export function findComponents(components, query) { console.warn('formio.js/utils findComponents is deprecated. Use searchComponents instead.'); return searchComponents(components, query); } -/** - * This function will find a component in a form and return the component AND THE PATH to the component in the form. - * Path to the component is stored as an array of nested components and their indexes.The Path is being filled recursively - * when you iterating through the nested structure. - * If the component is not found the callback won't be called and function won't return anything. - * - * @param components - * @param key - * @param fn - * @param path - * @returns {*} - */ -export function findComponent(components, key, path, fn) { - if (!components) return; - path = path || []; - - if (!key) { - return fn(components); - } - - components.forEach(function(component, index) { - var newPath = path.slice(); - // Add an index of the component it iterates through in nested structure - newPath.push(index); - if (!component) return; - - if (component.hasOwnProperty('columns') && Array.isArray(component.columns)) { - newPath.push('columns'); - component.columns.forEach(function(column, index) { - var colPath = newPath.slice(); - colPath.push(index); - colPath.push('components'); - findComponent(column.components, key, colPath, fn); - }); - } - - if (component.hasOwnProperty('rows') && Array.isArray(component.rows)) { - newPath.push('rows'); - component.rows.forEach(function(row, index) { - var rowPath = newPath.slice(); - rowPath.push(index); - row.forEach(function(column, index) { - var colPath = rowPath.slice(); - colPath.push(index); - colPath.push('components'); - findComponent(column.components, key, colPath, fn); - }); - }); - } - - if (component.hasOwnProperty('components') && Array.isArray(component.components)) { - newPath.push('components'); - findComponent(component.components, key, newPath, fn); - } - - if (component.key === key) { - //Final callback if the component is found - fn(component, newPath, components); - } - }); -} - -/** - * Remove a component by path. - * - * @param components - * @param path - */ -export function removeComponent(components, path) { - // Using _.unset() leave a null value. Use Array splice instead. - var index = path.pop(); - if (path.length !== 0) { - components = get(components, path); - } - components.splice(index, 1); -} - -export function generateFormChange(type, data) { - let change; - switch (type) { - case 'add': - change = { - op: 'add', - key: data.component.key, - container: data.parent.key, // Parent component - path: data.path, // Path to container within parent component. - index: data.index, // Index of component in parent container. - component: data.component - }; - break; - case 'edit': - change = { - op: 'edit', - key: data.originalComponent.key, - patches: compare(data.originalComponent, data.component) - }; - - // Don't save if nothing changed. - if (!change.patches.length) { - change = null; - } - break; - case 'remove': - change = { - op: 'remove', - key: data.component.key, - }; - break; - } - - return change; -} - -export function applyFormChanges(form, changes) { - const failed = []; - changes.forEach(function(change) { - var found = false; - switch (change.op) { - case 'add': - var newComponent = change.component; - - // Find the container to set the component in. - findComponent(form.components, change.container, null, function(parent) { - if (!change.container) { - parent = form; - } - - // A move will first run an add so remove any existing components with matching key before inserting. - findComponent(form.components, change.key, null, function(component, path) { - // If found, use the existing component. (If someone else edited it, the changes would be here) - newComponent = component; - removeComponent(form.components, path); - }); - - found = true; - var container = get(parent, change.path); - container.splice(change.index, 0, newComponent); - }); - break; - case 'remove': - findComponent(form.components, change.key, null, function(component, path) { - found = true; - const oldComponent = get(form.components, path); - if (oldComponent.key !== component.key) { - path.pop(); - } - removeComponent(form.components, path); - }); - break; - case 'edit': - findComponent(form.components, change.key, null, function(component, path) { - found = true; - try { - const oldComponent = get(form.components, path); - const newComponent = applyPatch(component, change.patches).newDocument; - - if (oldComponent.key !== newComponent.key) { - path.pop(); - } - - set(form.components, path, newComponent); - } - catch (err) { - failed.push(change); - } - }); - break; - case 'move': - break; - } - if (!found) { - failed.push(change); - } - }); - - return { - form, - failed - }; -} - -/** - * Flatten the form components for data manipulation. - * - * @param {Object} components - * The components to iterate. - * @param {Boolean} includeAll - * Whether or not to include layout components. - * - * @returns {Object} - * The flattened components map. - */ -export function flattenComponents(components, includeAll = false) { - const flattened = {}; - eachComponent(components, (component, path) => { - flattened[path] = component; - }, includeAll); - return flattened; -} - -/** - * Returns if this component has a conditional statement. - * - * @param component - The component JSON schema. - * - * @returns {boolean} - TRUE - This component has a conditional, FALSE - No conditional provided. - */ -export function hasCondition(component) { - return Boolean( - (component.customConditional) || - (component.conditional && (component.conditional.when || - (_.some(component.conditional.conditions || [], (condition => condition.component && condition.operator))) || - component.conditional.json || - component.conditional.condition - )) - ); -} - -/** - * Extension of standard #parseFloat(value) function, that also clears input string. - * - * @param {any} value - * The value to parse. - * - * @returns {Number} - * Parsed value. - */ -export function parseFloatExt(value) { - return parseFloat(isString(value) - ? value.replace(/[^\de.+-]/gi, '') - : value); -} - -/** - * Formats provided value in way how Currency component uses it. - * - * @param {any} value - * The value to format. - * - * @returns {String} - * Value formatted for Currency component. - */ -export function formatAsCurrency(value) { - const parsedValue = parseFloatExt(value); - - if (isNaN(parsedValue)) { - return ''; - } - - const parts = round(parsedValue, 2) - .toString() - .split('.'); - parts[0] = chunk(Array.from(parts[0]).reverse(), 3) - .reverse() - .map((part) => part - .reverse() - .join('')) - .join(','); - parts[1] = pad(parts[1], 2, '0'); - return parts.join('.'); -} - -/** - * Escapes RegEx characters in provided String value. - * - * @param {String} value - * String for escaping RegEx characters. - * @returns {string} - * String with escaped RegEx characters. - */ -export function escapeRegExCharacters(value) { - return value.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&'); -} - -/** - * Get the value for a component key, in the given submission. - * - * @param {Object} submission - * A submission object to search. - * @param {String} key - * A for components API key to search for. - */ -export function getValue(submission, key) { - const search = (data) => { - if (isPlainObject(data)) { - if (has(data, key)) { - return _.get(data, key); - } - - let value = null; - - forOwn(data, (prop) => { - const result = search(prop); - if (!isNil(result)) { - value = result; - return false; - } - }); - - return value; - } - else { - return null; - } - }; - - return search(submission.data); -} - -/** - * Iterate over all components in a form and get string values for translation. - * @param form - */ -export function getStrings(form) { - const properties = ['label', 'title', 'legend', 'tooltip', 'description', 'placeholder', 'prefix', 'suffix', 'errorLabel', 'content', 'html']; - const strings = []; - eachComponent(form.components, component => { - properties.forEach(property => { - if (component.hasOwnProperty(property) && component[property]) { - strings.push({ - key: component.key, - type: component.type, - property, - string: component[property] - }); - } - }); - if ((!component.dataSrc || component.dataSrc === 'values') && component.hasOwnProperty('values') && Array.isArray(component.values) && component.values.length) { - component.values.forEach((value, index) => { - strings.push({ - key: component.key, - property: `value[${index}].label`, - string: component.values[index].label - }); - }); - } - - // Hard coded values from Day component - if (component.type === 'day') { - [ - 'day', - 'month', - 'year', - 'Day', - 'Month', - 'Year', - 'january', - 'february', - 'march', - 'april', - 'may', - 'june', - 'july', - 'august', - 'september', - 'october', - 'november', - 'december' - ].forEach(string => { - strings.push({ - key: component.key, - property: 'day', - string, - }); - }); - - if (component.fields.day.placeholder) { - strings.push({ - key: component.key, - property: 'fields.day.placeholder', - string: component.fields.day.placeholder, - }); - } - - if (component.fields.month.placeholder) { - strings.push({ - key: component.key, - property: 'fields.month.placeholder', - string: component.fields.month.placeholder, - }); - } - - if (component.fields.year.placeholder) { - strings.push({ - key: component.key, - property: 'fields.year.placeholder', - string: component.fields.year.placeholder, - }); - } - } - - if (component.type === 'editgrid') { - const string = component.addAnother || 'Add Another'; - if (component.addAnother) { - strings.push({ - key: component.key, - property: 'addAnother', - string, - }); - } - } - - if (component.type === 'select') { - [ - 'loading...', - 'Type to search' - ].forEach(string => { - strings.push({ - key: component.key, - property: 'select', - string, - }); - }); - } - }, true); - - return strings; -} +export { + flattenComponents, + guid, + uniqueName, + MODEL_TYPES, + getModelType, + getComponentAbsolutePath, + getComponentPath, + isComponentModelType, + isComponentNestedDataType, + componentPath, + componentChildPath, + eachComponentDataAsync, + eachComponentData, + getComponentKey, + getContextualRowPath, + getContextualRowData, + componentInfo, + eachComponent, + eachComponentAsync, + getComponentData, + getComponentActualValue, + isLayoutComponent, + matchComponent, + getComponent, + searchComponents, + removeComponent, + hasCondition, + parseFloatExt, + formatAsCurrency, + escapeRegExCharacters, + getValue, + getStrings, + generateFormChange, + applyFormChanges, + findComponent, + getEmptyValue, + isComponentDataEmpty +}; diff --git a/src/utils/utils.js b/src/utils/utils.js index c06750eb3f..414c6c3b67 100644 --- a/src/utils/utils.js +++ b/src/utils/utils.js @@ -38,6 +38,10 @@ jsonLogic.add_operation('relativeMaxDate', (relativeMaxDate) => { export { jsonLogic, ConditionOperators }; export * as moment from 'moment-timezone/moment-timezone'; +/** + * Sets the path to the component and parent schema. + * @param {import('@formio/core').Component} component - The component to set the path for. + */ function setPathToComponentAndPerentSchema(component) { component.path = getComponentPath(component); const dataParent = getDataParentComponent(component); @@ -48,10 +52,11 @@ function setPathToComponentAndPerentSchema(component) { /** * Evaluate a method. - * - * @param func - * @param args - * @return {*} + * @param {Function|string|object} func - The function to evaluate. + * @param {*} args - A map of arguments to pass to the function. + * @param {string} ret - The name of the "return" variable in the script. + * @param {boolean} tokenize - True if the script should be interpolated before being executed. + * @returns {*} - The result of the evaluation. */ export function evaluate(func, args, ret, tokenize) { let returnVal = null; @@ -117,16 +122,19 @@ export function evaluate(func, args, ret, tokenize) { return returnVal; } +/** + * Returns a random compoennt ID. + * @returns {string} - A random component ID. + */ export function getRandomComponentId() { return `e${Math.random().toString(36).substring(7)}`; } /** * Get a property value of an element. - * - * @param style - * @param prop - * @return {number} + * @param {CSSStyleDeclaration} style - The style element to get the property value from. + * @param {string} prop - The property to get the value for. + * @returns {number} - The value of the property. */ export function getPropertyValue(style, prop) { let value = style.getPropertyValue(prop); @@ -136,9 +144,8 @@ export function getPropertyValue(style, prop) { /** * Get an elements bounding rectagle. - * - * @param element - * @return {{x: string, y: string, width: string, height: string}} + * @param {HTMLElement} element - A DOM element to get the bounding rectangle for. + * @returns {{x: number, y: number, width: number, height: number}} - The bounding rectangle. */ export function getElementRect(element) { const style = window.getComputedStyle(element, null); @@ -152,9 +159,8 @@ export function getElementRect(element) { /** * Determines the boolean value of a setting. - * - * @param value - * @return {boolean} + * @param {string|boolean} value - A string or boolean value to convert to boolean. + * @returns {boolean} - The boolean value of the setting. */ export function boolValue(value) { if (_.isBoolean(value)) { @@ -170,22 +176,18 @@ export function boolValue(value) { /** * Check to see if an ID is a mongoID. - * @param text - * @return {Array|{index: number, input: string}|Boolean|*} + * @param {string} text - The text to check if it is a mongoID. + * @returns {boolean} - TRUE if the text is a mongoID; FALSE otherwise. */ export function isMongoId(text) { - return text.toString().match(/^[0-9a-fA-F]{24}$/); + return !!text.toString().match(/^[0-9a-fA-F]{24}$/); } /** * Checks the calculated value for a provided component and data. - * - * @param {Object} component - * The component to check for the calculated value. - * @param {Object} submission - * A submission object. - * @param data - * The full submission data. + * @param {import('@formio/core').Component} component - The component to check for the calculated value. + * @param {import('@formio/core').Submission} submission - A submission object. + * @param {*} rowData - The contextual row data for the component. */ export function checkCalculated(component, submission, rowData) { // Process calculated value stuff if present. @@ -201,14 +203,13 @@ export function checkCalculated(component, submission, rowData) { } /** - * Check if a simple conditional evaluates to true. - * - * @param condition - * @param condition - * @param row - * @param data - * @param instance - * @returns {boolean} + * Check if a simple conditional evaluates to true. + * @param {import('@formio/core').Component} component - The component to check for the conditional. + * @param {import('@formio/core').SimpleConditional} condition - The condition to check. + * @param {*} row - The row data for the component. + * @param {*} data - The full submission data. + * @param {import('../../src/components/_classes/component/Component').Component} instance - The instance of the component. + * @returns {boolean} - TRUE if the condition is true; FALSE otherwise. */ export function checkSimpleConditional(component, condition, row, data, instance) { if (condition.when) { @@ -262,6 +263,13 @@ export function checkCalculated(component, submission, rowData) { } } +/** + * Returns a components normalized value. + * @param {string} compPath - The full path to the component. + * @param {*} data - The data object to get the value from. + * @param {*} row - The contextual row data for the component. + * @returns {*} - The normalized value of the component. + */ export function getComponentActualValue(compPath, data, row) { let value = null; @@ -280,12 +288,15 @@ export function getComponentActualValue(compPath, data, row) { /** * Check custom javascript conditional. - * - * @param component - * @param custom - * @param row - * @param data - * @returns {*} + * @param {import('@formio/core').Component} component - The component to check for the conditional. + * @param {string} custom - The custom conditional string to evaluate. + * @param {*} row - The row data for the component. + * @param {*} data - The full submission data. + * @param {import('@formio/core').Form} form - The form object. + * @param {string} variable - The variable name for the result of the custom conditional. + * @param {*} onError - A custom return if there is an error or the value is null from the evaluation. + * @param {import('../../src/components/_classes/component/Component').Component} instance - The component instance. + * @returns {*} - The result of the evaulation. */ export function checkCustomConditional(component, custom, row, data, form, variable, onError, instance) { if (typeof custom === 'string') { @@ -300,6 +311,16 @@ export function checkCustomConditional(component, custom, row, data, form, varia return value; } +/** + * Check a component for JSON conditionals. + * @param {import('@formio/core').Component} component - The component + * @param {import('@formio/core').JSONConditional} json - The json conditional to check. + * @param {*} row - The contextual row data for the component. + * @param {*} data - The full submission data. + * @param {import('@formio/core').Form} form - The Form JSON of the form. + * @param {*} onError - Custom return value if there is an error. + * @returns {boolean} - TRUE if the condition is true; FALSE otherwise. + */ export function checkJsonConditional(component, json, row, data, form, onError) { try { return jsonLogic.apply(json, { @@ -315,6 +336,14 @@ export function checkJsonConditional(component, json, row, data, form, onError) } } +/** + * Returns the contextual row data for a component. + * @param {import('@formio/core').Component} component - The component to get the row data for. + * @param {*} row - The row data for the component. + * @param {import('../../src/components/_classes/component/Component').Component} instance - The component instance. + * @param {*} conditional - The component conditional. + * @returns {*} - The contextual row data for the component. + */ function getRow(component, row, instance, conditional) { const condition = conditional || component.conditional; // If no component's instance passed (happens only in 6.x server), calculate its path based on the schema @@ -339,15 +368,12 @@ function getRow(component, row, instance, conditional) { /** * Checks the conditions for a provided component and data. - * - * @param component - * The component to check for the condition. - * @param row - * The data within a row - * @param data - * The full submission data. - * - * @returns {boolean} + * @param {import('@formio/core').Component} component - The component to check for the condition. + * @param {*} row - The data within a row + * @param {*} data - The full submission data. + * @param {import('@formio/core').Form} form - The form object. + * @param {import('../../src/components/_classes/component/Component').Component} instance - The component instance. + * @returns {boolean} - TRUE if the condition is true; FALSE otherwise. */ export function checkCondition(component, row, data, form, instance) { const { customConditional, conditional } = component; @@ -368,12 +394,13 @@ export function checkCondition(component, row, data, form, instance) { /** * Test a trigger on a component. - * - * @param component - * @param action - * @param data - * @param row - * @returns {mixed} + * @param {import('@formio/core').Component} component - The component to test the trigger against. + * @param {import('@formio/core').LogicTrigger} trigger - The trigger configuration. + * @param {import('@formio/core').DataObject} row - The contextual row data. + * @param {import('@formio/core').DataObject} data - The root data object. + * @param {import('@formio/core').Form} form - The form object. + * @param {any} instance - The component that is performing the trigger. + * @returns {boolean} - TRUE if the trigger should fire; FALSE otherwise. */ export function checkTrigger(component, trigger, row, data, form, instance) { // If trigger is empty, don't fire it @@ -394,6 +421,16 @@ export function checkTrigger(component, trigger, row, data, form, instance) { return false; } +/** + * Sets a property on a component via an executed Logic action. + * @param {import('@formio/core').Component} component - The component to set the property on. + * @param {import('@formio/core').LogicAction} action - The action to perform on the component. + * @param {string} result - The name of the variable in the evaulation to use as the result. + * @param {import('@formio/core').DataObject} row - The contextual row data. + * @param {import('@formio/core').DataObject} data - The full submission data. + * @param {any} instance - The component instance. + * @returns {import('@formio/core').Component} - The modified component. + */ export function setActionProperty(component, action, result, row, data, instance) { const property = action.property.value; @@ -434,8 +471,8 @@ export function setActionProperty(component, action, result, row, data, instance /** * Unescape HTML characters like <, >, & and etc. - * @param str - * @returns {string} + * @param {string} str - The string to unescape. + * @returns {string} - The unescaped string. */ export function unescapeHTML(str) { if (typeof window === 'undefined' || !('DOMParser' in window)) { @@ -448,11 +485,10 @@ export function unescapeHTML(str) { /** * Make HTML element from string - * @param str - * @param selector - * @returns {HTMLElement} + * @param {string} str - The string to convert to an HTML element. + * @param {string} selector - The selector to use to get the element once it is created. + * @returns {HTMLElement} - The HTML element that was created. */ - export function convertStringToHTMLElement(str, selector) { const doc = new window.DOMParser().parseFromString(str, 'text/html'); return doc.body.querySelector(selector); @@ -460,10 +496,10 @@ export function convertStringToHTMLElement(str, selector) { /** * Make a filename guaranteed to be unique. - * @param name - * @param template - * @param evalContext - * @returns {string} + * @param {string} name - The original name of the file. + * @param {string} template - The template to use for the unique name. + * @param {object} evalContext - The context to use for the evaluation. + * @returns {string} - A unique filename. */ export function uniqueName(name, template, evalContext) { template = template || '{{fileName}}-{{guid}}'; @@ -487,6 +523,10 @@ export function uniqueName(name, template, evalContext) { return uniqueName; } +/** + * Returns a GUID + * @returns {string} - A GUID. + */ export function guid() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { const r = Math.random()*16|0; @@ -499,9 +539,8 @@ export function guid() { /** * Return a translated date setting. - * - * @param date - * @return {(null|Date)} + * @param {string|Date} date - The date to translate. + * @returns {(null|Date)} - The translated date. */ export function getDateSetting(date) { if (_.isNil(date) || _.isNaN(date) || date === '') { @@ -549,14 +588,18 @@ export function getDateSetting(date) { return dateSetting.toDate(); } +/** + * Returns true if the date is a valid date. False otherwise. + * @param {Date|string} date - The date to check for validity. + * @returns {boolean} - TRUE if the date is valid; FALSE otherwise. + */ export function isValidDate(date) { return _.isDate(date) && !_.isNaN(date.getDate()); } /** * Get the current timezone string. - * - * @return {string} + * @returns {string} - The current timezone. */ export function currentTimezone() { if (moment.currentTimezone) { @@ -568,10 +611,9 @@ export function currentTimezone() { /** * Get an offset date provided a date object and timezone object. - * - * @param date - * @param timezone - * @return {Date} + * @param {Date} date - The date to offset. + * @param {string} timezone - The timezone to offset the date to. + * @returns {Date} - The offset date. */ export function offsetDate(date, timezone) { if (timezone === 'UTC') { @@ -589,8 +631,7 @@ export function offsetDate(date, timezone) { /** * Returns if the zones are loaded. - * - * @return {boolean} + * @returns {boolean} - TRUE if the zones are loaded; FALSE otherwise. */ export function zonesLoaded() { return moment.zonesLoaded; @@ -598,9 +639,8 @@ export function zonesLoaded() { /** * Returns if we should load the zones. - * - * @param timezone - * @return {boolean} + * @param {string} timezone - The timezone to check if we should load the zones. + * @returns {boolean} - TRUE if we should load the zones; FALSE otherwise. */ export function shouldLoadZones(timezone) { if (timezone === currentTimezone() || timezone === 'UTC') { @@ -611,8 +651,9 @@ export function shouldLoadZones(timezone) { /** * Externally load the timezone data. - * - * @return {Promise | *} + * @param {string} url - The URL to load the timezone data from. + * @param {string} timezone - The timezone to load. + * @returns {Promise | *} - Resolves when the zones for this timezone are loaded. */ export function loadZones(url, timezone) { if (timezone && !shouldLoadZones(timezone)) { @@ -639,11 +680,10 @@ export function loadZones(url, timezone) { /** * Get the moment date object for translating dates with timezones. - * - * @param value - * @param format - * @param timezone - * @return {*} + * @param {string|Date} value - The value to convert into a moment date. + * @param {string} format - The format to convert the date to. + * @param {string} timezone - The timezone to convert the date to. + * @returns {Date} - The moment date object. */ export function momentDate(value, format, timezone) { const momentDate = moment(value); @@ -661,11 +701,12 @@ export function momentDate(value, format, timezone) { /** * Format a date provided a value, format, and timezone object. - * - * @param value - * @param format - * @param timezone - * @return {string} + * @param {string} timezonesUrl - The URL to load the timezone data from. + * @param {string|Date} value - The value to format. + * @param {string} format - The format to format the date to. + * @param {string} timezone - The timezone to format the date to. + * @param {string} flatPickrInputFormat - The format to use for flatpickr input. + * @returns {string} - The formatted date. */ export function formatDate(timezonesUrl, value, format, timezone, flatPickrInputFormat) { const momentDate = moment(value, flatPickrInputFormat || undefined); @@ -701,12 +742,12 @@ export function formatDate(timezonesUrl, value, format, timezone, flatPickrInput /** * Pass a format function to format within a timezone. - * - * @param formatFn - * @param date - * @param format - * @param timezone - * @return {string} + * @param {string} timezonesUrl - The URL to load the timezone data from. + * @param {Function} formatFn - The format function to use. + * @param {Date|string} date - The date to format. + * @param {string} format - The format to format the date to. + * @param {string} timezone - The timezone to format the date to. + * @returns {string} - The formatted date. */ export function formatOffset(timezonesUrl, formatFn, date, format, timezone) { if (timezone === currentTimezone()) { @@ -727,6 +768,11 @@ export function formatOffset(timezonesUrl, formatFn, date, format, timezone) { } } +/** + * Returns the local date format information. + * @param {Intl.LocalesArgument} locale - The locale to get the date format for. + * @returns {object} - The local date format information. + */ export function getLocaleDateFormatInfo(locale) { const formatInfo = {}; @@ -741,8 +787,8 @@ export function getLocaleDateFormatInfo(locale) { /** * Convert the format from the angular-datepicker module to flatpickr format. - * @param format - * @return {string} + * @param {string} format - The format to convert. + * @returns {string} - The converted format. */ export function convertFormatToFlatpickr(format) { return format @@ -778,8 +824,8 @@ export function convertFormatToFlatpickr(format) { /** * Convert the format from the angular-datepicker module to moment format. - * @param format - * @return {string} + * @param {string} format - The format to convert. + * @returns {string} - The converted format. */ export function convertFormatToMoment(format) { return format @@ -795,6 +841,11 @@ export function convertFormatToMoment(format) { .replace(/U/g, 'X'); } +/** + * Convert the format from the angular-datepicker module to mask format. + * @param {string} format - The format to convert. + * @returns {string} - The converted format. + */ export function convertFormatToMask(format) { return format // Long month replacement. @@ -854,6 +905,13 @@ export function getInputMask(mask, placeholderChar) { return maskArray; } +/** + * Unmasks a value using the provided mask and placeholder characters. + * @param {string} value - The value to unmask. + * @param {string} mask - The mask to use for unmasking. + * @param {string} placeholderChar - The placeholder character to use for unmasking. + * @returns {string} - The unmasked value. + */ export function unmaskValue(value, mask, placeholderChar) { if (!mask || !value || value.length > mask.length) { return value; @@ -875,6 +933,12 @@ export function unmaskValue(value, mask, placeholderChar) { return unmaskedValue; } +/** + * Returns true if the value matches the input mask format. + * @param {string} value - The value to check. + * @param {string} inputMask - The input mask to check against. + * @returns {boolean} - TRUE if the value matches the input mask; FALSE otherwise. + */ export function matchInputMask(value, inputMask) { if (!inputMask) { return true; @@ -897,6 +961,11 @@ export function matchInputMask(value, inputMask) { return true; } +/** + * Returns the number separators (i.e. 1,000) for the provided language. + * @param {string} lang - The language code to get the number separators for. + * @returns {{delimiter: string, decimalSeparator: string}} - The number separators. + */ export function getNumberSeparators(lang = 'en') { const formattedNumberString = (12345.6789).toLocaleString(lang); const delimeters = formattedNumberString.match(/..(.)...(.)../); @@ -912,6 +981,12 @@ export function getNumberSeparators(lang = 'en') { }; } +/** + * Returns the number for the maximum amount of decimal places for a number. + * @param {import('@formio/core').Component} component - The component to check for decimal limits. + * @param {number} defaultLimit - The default limit to use if none is provided in the component. + * @returns {number} - The number of decimal places allowed. + */ export function getNumberDecimalLimit(component, defaultLimit) { if (_.has(component, 'decimalLimit')) { return _.get(component, 'decimalLimit'); @@ -930,6 +1005,15 @@ export function getNumberDecimalLimit(component, defaultLimit) { return decimalLimit; } +/** + * Returns the currency affixes for a specific language. + * @param {object} arg0 - The arguments object. + * @param {string} arg0.currency - The currency code to get the affixes for. + * @param {number} arg0.decimalLimit - The number of decimal places to use. + * @param {string} arg0.decimalSeparator - The decimal separator to use. + * @param {string} arg0.lang - The language code to use. + * @returns {{prefix: string, suffix: string}} - The currency affixes. + */ export function getCurrencyAffixes({ currency, decimalLimit, @@ -957,10 +1041,9 @@ export function getCurrencyAffixes({ /** * Fetch the field data provided a component. - * - * @param data - * @param component - * @return {*} + * @param {import('@formio/core').DataObject} data - The data object to fetch the field data from. + * @param {import('@formio/core').Component} component - The component to fetch the field data for. + * @returns {*} - The field data. */ export function fieldData(data, component) { if (!data) { @@ -1013,18 +1096,25 @@ export function fieldData(data, component) { /** * Delays function execution with possibility to execute function synchronously or cancel it. - * - * @param fn Function to delay - * @param delay Delay time - * @return {*} + * @param {Function} fn - Function to delay + * @param {number} delay - Delay time + * @param {...any} args - Arguments to pass to the function + * @returns {*} - Function to cancel the delay */ export function delay(fn, delay = 0, ...args) { const timer = setTimeout(fn, delay, ...args); + /** + * + */ function cancel() { clearTimeout(timer); } + /** + * Execute the function early. + * @returns {*} - The result of the function. + */ function earlyCall() { cancel(); return fn(...args); @@ -1038,11 +1128,9 @@ export function delay(fn, delay = 0, ...args) { /** * Iterate the given key to make it unique. - * - * @param {String} key + * @param {string} key * Modify the component key to be unique. - * - * @returns {String} + * @returns {string} * The new component key. */ export function iterateKey(key) { @@ -1057,10 +1145,9 @@ export function iterateKey(key) { /** * Determines a unique key within a map provided the base key. - * - * @param map - * @param base - * @return {*} + * @param {Record} map - The map to check for uniqueness. + * @param {string} base - The base path of the key. + * @returns {string} - The unique key. */ export function uniqueKey(map, base) { let newKey = base; @@ -1072,8 +1159,9 @@ export function uniqueKey(map, base) { /** * Determines the major version number of bootstrap. - * - * @return {number} + * @param {object} options - The options to check for bootstrap version. + * @param {string} options.bootstrap - The bootstrap version to use. + * @returns {number} - The bootstrap version. */ export function bootstrapVersion(options) { if (options.bootstrap) { @@ -1091,9 +1179,8 @@ export function bootstrapVersion(options) { /** * Retrun provided argument. * If argument is a function, returns the result of a function call. - * @param {*} e; - * - * @return {*} + * @param {Function|any} e - The argument to check if a function and call if so. + * @returns {any} - Either the result of the function call (e) or e if it is not a function. */ export function unfold(e) { if (typeof e === 'function') { @@ -1105,30 +1192,35 @@ export function unfold(e) { /** * Map values through unfold and return first non-nil value. - * @param {Array} collection; - * - * @return {T} + * @param {Array} collection - The collection to map through unfold.; + * @returns {T} - The first non-nil value. */ export const firstNonNil = _.flow([ _.partialRight(_.map, unfold), _.partialRight(_.find, v => !_.isUndefined(v)) ]); -/* - * Create enclosed state. - * Returns functions to getting and cycling between states. +/** + * Create enclosed state. Returns functions to getting and cycling between states. * @param {*} a - initial state. * @param {*} b - next state. - * @return {Functions[]} -- [get, toggle]; + * @returns {Functions[]} -- [get, toggle]; */ export function withSwitch(a, b) { let state = a; let next = b; + /** + * Returns the state of the switch. + * @returns {*} - The current state. + */ function get() { return state; } + /** + * Toggles the state of the switch. + */ function toggle() { const prev = state; state = next; @@ -1138,6 +1230,14 @@ export function withSwitch(a, b) { return [get, toggle]; } +/** + * Create a function that will call the provided function only the provided limit. + * @param {Function} callback - The callback to call. + * @param {object} options - The options to use. + * @param {number} options.limit - The limit to call the callback. + * @param {number} options.delay - The delay to wait before resetting the call count. + * @returns {Function} - The function that will call the callback only the provided limit. + */ export function observeOverload(callback, options = {}) { const { limit = 50, delay = 500 } = options; let callCount = 0; @@ -1163,6 +1263,13 @@ export function observeOverload(callback, options = {}) { }; } +/** + * Returns the components that are provided within an evaluation context. + * @param {any} context - The evaluation context to get the components from. + * @param {boolean} excludeNested - Exclude nested components. + * @param {Array} excludedTypes - The types of components to exclude. + * @returns {Array} - The components within the evaluation context. + */ export function getContextComponents(context, excludeNested, excludedTypes = []) { const values = []; @@ -1179,6 +1286,11 @@ export function getContextComponents(context, excludeNested, excludedTypes = []) return values; } +/** + * Returns the button components that are within an evaluation context. + * @param {any} context - The evaluation context to get the components from. + * @returns {Array} - The button components within the evaluation context. + */ export function getContextButtons(context) { const values = []; @@ -1199,12 +1311,9 @@ const inTextTags = ['#text', 'A', 'B', 'EM', 'I', 'SMALL', 'STRONG', 'SUB', 'SUP /** * Helper function for 'translateHTMLTemplate'. Translates text value of the passed html element. - * - * @param {HTMLElement} elem - * @param {Function} translate - * - * @returns {String} - * Translated element template. + * @param {HTMLElement} elem - The element to translate. + * @param {Function} translate - The translation function. + * @returns {string} - Translated element template. */ function translateElemValue(elem, translate) { if (!elem.innerText) { @@ -1241,10 +1350,8 @@ function translateElemValue(elem, translate) { /** * Helper function for 'translateHTMLTemplate'. Goes deep through html tag children and calls function to translate their text values. - * - * @param {HTMLElement} tag - * @param {Function} translate - * + * @param {HTMLElement} tag - The tag to translate. + * @param {Function} translate - The translation function. * @returns {void} */ function translateDeepTag(tag, translate) { @@ -1264,12 +1371,9 @@ function translateDeepTag(tag, translate) { /** * Translates text values in html template. - * - * @param {String} template - * @param {Function} translate - * - * @returns {String} - * Html template with translated values. + * @param {string} template - The template to translate. + * @param {Function} translate - The translation function. + * @returns {string} - Html template with translated values. */ export function translateHTMLTemplate(template, translate) { const isHTML = /<[^>]*>/.test(template); @@ -1291,9 +1395,9 @@ export function translateHTMLTemplate(template, translate) { /** * Sanitize an html string. - * - * @param string - * @returns {*} + * @param {string} string - The string to sanitize. + * @param {any} options - The options to use for sanitization. + * @returns {string} - The sanitized html string. */ export function sanitize(string, options) { if (typeof dompurify.sanitize !== 'function') { @@ -1342,6 +1446,8 @@ export function sanitize(string, options) { /** * Fast cloneDeep for JSON objects only. + * @param {any} obj - The object to perform a fast clone deep against. + * @returns {any} - The cloned object. */ export function fastCloneDeep(obj) { return obj ? JSON.parse(JSON.stringify(obj)) : obj; @@ -1349,6 +1455,11 @@ export function fastCloneDeep(obj) { export { Evaluator, interpolate }; +/** + * Returns if the component is an input component. + * @param {import('@formio/core').Component} componentJson - The JSON of a component. + * @returns {bool} - TRUE if the component is an input component; FALSE otherwise. + */ export function isInputComponent(componentJson) { if (componentJson.input === false || componentJson.input === true) { return componentJson.input; @@ -1369,6 +1480,11 @@ export function isInputComponent(componentJson) { } } +/** + * Takes a component path, and returns a component path array. + * @param {string} pathStr - The path string to convert to an array. + * @returns {Arryay} - The array of paths. + */ export function getArrayFromComponentPath(pathStr) { if (!pathStr || !_.isString(pathStr)) { if (!_.isArray(pathStr)) { @@ -1383,6 +1499,12 @@ export function getArrayFromComponentPath(pathStr) { .map(part => _.defaultTo(_.toNumber(part), part)); } +/** + * Returns true if the component is a child of the parent. + * @param {any} child - The child component to check. + * @param {any} parent - The parent component to check. + * @returns {boolean} - TRUE if the child is a child of the parent; FALSE otherwise. + */ export function isChildOf(child, parent) { while (child && child.parent) { if (child.parent === parent) { @@ -1393,6 +1515,11 @@ export function isChildOf(child, parent) { return false; } +/** + * Takes an array of component path indexes, and returns a string version of that array. + * @param {Array} path - The path array to convert to a string. + * @returns {string} - The string version of the path. + */ export function getStringFromComponentPath(path) { if (!_.isArray(path)) { return path; @@ -1409,17 +1536,22 @@ export function getStringFromComponentPath(path) { return strPath; } +/** + * Takes a number and rounds it to the provided precision amount. + * @param {number} number - The number to round. + * @param {number} precision - The precision to round the number to. + * @returns {string} - The rounded number. + */ export function round(number, precision) { if (_.isNumber(number)) { return number.toFixed(precision); } - return number; + return number.toString(); } /** * Check for Internet Explorer browser version - * - * @return {(number|null)} + * @returns {(number|null)} - The IE browser version or null if not IE */ export function getIEBrowserVersion() { const { ie, version } = getBrowserInfo(); @@ -1429,8 +1561,7 @@ export function getIEBrowserVersion() { /** * Get browser name and version (modified from 'jquery-browser-plugin') - * - * @return {Object} -- {{browser name, version, isWebkit?}} + * @returns {object} -- {{browser name, version, isWebkit?}} * Possible browser names: chrome, safari, ie, edge, opera, mozilla, yabrowser */ export function getBrowserInfo() { @@ -1483,13 +1614,20 @@ export function getBrowserInfo() { return browser; } +/** + * Takes a component path, which may include array indicies (i.e. [0][1]), and returns the compoennt path without the indicies. + * @param {string} path - The path to remove the indicies from. + * @returns {string} - The path without the indicies. + */ export function getComponentPathWithoutIndicies(path = '') { return path.replace(/\[\d+\]/, ''); } /** * Returns a path to the component which based on its schema - * @param {*} component is a component's schema containing link to its parent's schema in the 'parent' property + * @param {import('@formio/core').Component} component - Component containing link to its parent's schema in the 'parent' property + * @param {string} path - Path to the component + * @returns {string} - Path to the component */ export function getComponentPath(component, path = '') { if (!component || !component.key || component?._form?.display === 'wizard') { // unlike the Webform, the Wizard has the key and it is a duplicate of the panel key @@ -1501,8 +1639,8 @@ export function getComponentPath(component, path = '') { /** * Returns a parent component of the passed component instance skipping all the Layout components - * @param {*} componentInstance - * @return {(Component|undefined)} + * @param {Component} componentInstance - The component to check for the parent. + * @returns {Component|undefined} - The parent data component. */ export function getDataParentComponent(componentInstance) { if (!componentInstance) { @@ -1519,8 +1657,8 @@ export function getDataParentComponent(componentInstance) { /** * Returns whether the value is a promise - * @param value - * @return {boolean} + * @param {any} value - The value to check + * @returns {boolean} - TRUE if the value is a promise; FALSE otherwise */ export function isPromise(value) { return value @@ -1532,9 +1670,9 @@ export function getDataParentComponent(componentInstance) { /** * Determines if the component has a scoping parent in tree (a component which scopes its children and manages its * changes by itself, e.g. EditGrid) - * @param componentInstance - * @param firstPass - * @returns {boolean|boolean|*} + * @param {Component} componentInstance - The component to check for the scoping parent. + * @param {boolean} firstPass - Whether it is the first pass of the function + * @returns {boolean|*} - TRUE if the component has a scoping parent; FALSE otherwise */ export function isInsideScopingComponent(componentInstance, firstPass = true) { if (!firstPass && componentInstance?.hasScopedChildren) { @@ -1550,6 +1688,11 @@ export function isInsideScopingComponent(componentInstance, firstPass = true) { return false; } +/** + * Returns all the focusable elements within the provided dom element. + * @param {HTMLElement} element - The element to get the focusable elements from. + * @returns {NodeList} - The focusable elements within the provided element. + */ export function getFocusableElements(element) { const focusableSelector = `button:not([disabled]), input:not([disabled]), select:not([disabled]), @@ -1570,6 +1713,11 @@ export const componentValueTypes = { any: 'any', }; +/** + * Returns the saved types for the component + * @param {import('@formio/core').Component} fullSchema - The component schema + * @returns {Array|null} - The saved types for the component + */ export function getComponentSavedTypes(fullSchema) { const schema = fullSchema || {}; @@ -1586,9 +1734,10 @@ export function getComponentSavedTypes(fullSchema) { /** * Interpolates @formio/core errors so that they are compatible with the renderer - * @param {FieldError[]} errors - * @param firstPass - * @returns {[]} + * @param {Component} component - The component to interpolate the errors for + * @param {FieldError[]} errors - The errors to interpolate + * @param {Function} interpolateFn - The interpolation function + * @returns {[]} - The interpolated errors */ export const interpolateErrors = (component, errors, interpolateFn) => { return errors.map((error) => { @@ -1599,6 +1748,11 @@ export const interpolateErrors = (component, errors, interpolateFn) => { }); }; +/** + * Returns the template keys inside the template code. + * @param {string} template - The template to get the keys from. + * @returns {Array} - The keys inside the template. + */ export function getItemTemplateKeys(template) { const templateKeys = []; if (!template) { @@ -1618,6 +1772,11 @@ export function getItemTemplateKeys(template) { return templateKeys; } +/** + * Returns if the component is a select resource with an object for its value. + * @param {import('@formio/core').Component} comp - The component to check. + * @returns {boolean} - TRUE if the component is a select resource with an object for its value; FALSE otherwise. + */ export function isSelectResourceWithObjectValue(comp = {}) { const { reference, dataSrc, valueProperty } = comp; return reference || (dataSrc === 'resource' && (!valueProperty || valueProperty === 'data')); diff --git a/src/widgets/CalendarWidget.js b/src/widgets/CalendarWidget.js index 9113387b3c..2479711dff 100644 --- a/src/widgets/CalendarWidget.js +++ b/src/widgets/CalendarWidget.js @@ -69,8 +69,7 @@ export default class CalendarWidget extends InputWidget { /** * Load the timezones. - * - * @return {boolean} TRUE if the zones are loading, FALSE otherwise. + * @returns {boolean} TRUE if the zones are loading, FALSE otherwise. */ loadZones() { const timezone = this.timezone; @@ -308,11 +307,11 @@ export default class CalendarWidget extends InputWidget { } /** - * Return the date value. - * - * @param date - * @param format - * @return {string} + * Return the date value as a string. + * @param {string|Date} date - The date object or a date string that is momentjs compatible. + * @param {string} format - The DateParser code format. + * @param {boolean} [useTimezone] - If the timezone should be used. + * @returns {string} - Returns the formatted date string. */ getDateValue(date, format, useTimezone) { if (useTimezone) { @@ -323,8 +322,7 @@ export default class CalendarWidget extends InputWidget { /** * Return the value of the selected date. - * - * @return {*} + * @returns {*} - The value of the selected date. */ getValue() { // Standard output format. @@ -351,8 +349,8 @@ export default class CalendarWidget extends InputWidget { /** * Set the selected date value. - * - * @param value + * @param {*} value - The value to set. + * @returns {void} */ setValue(value) { const saveAsText = (this.settings.saveAs === 'text'); diff --git a/yarn.lock b/yarn.lock index d34ee45783..5071131e3a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15,7 +15,7 @@ "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.24" -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.23.5", "@babel/code-frame@^7.24.1", "@babel/code-frame@^7.24.2": +"@babel/code-frame@^7.23.5", "@babel/code-frame@^7.24.1", "@babel/code-frame@^7.24.2": version "7.24.2" resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz#718b4b19841809a58b29b68cde80bc5e1aa6d9ae" integrity sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ== @@ -219,6 +219,15 @@ resolved "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== +"@es-joy/jsdoccomment@~0.42.0": + version "0.42.0" + resolved "https://registry.yarnpkg.com/@es-joy/jsdoccomment/-/jsdoccomment-0.42.0.tgz#59e878708336aaee88c2b34c894f73dbf77ae2b0" + integrity sha512-R1w57YlVA6+YE01wch3GPYn6bCsrOV3YW/5oGGE2tmX6JcL9Nr+b5IikrjMPF+v9CV3ay+obImEdsDhovhJrzw== + dependencies: + comment-parser "1.4.1" + esquery "^1.5.0" + jsdoc-type-pratt-parser "~4.0.0" + "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" @@ -793,11 +802,6 @@ resolved "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== -abab@^1.0.0: - version "1.0.4" - resolved "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz#5faad9c2c07f60dd76770f71cf025b62a63cfd4e" - integrity sha512-I+Wi+qiE2kUXyrRhNsWv6XsjUTBJjSoVSctKNBfLG5zG/Xe7Rjbxf13+vqYHNTwHaFU+FtSlVxOCTiMEVtPv0A== - abab@^2.0.0, abab@^2.0.6: version "2.0.6" resolved "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" @@ -831,13 +835,6 @@ acorn-es7-plugin@^1.0.12: resolved "https://registry.npmjs.org/acorn-es7-plugin/-/acorn-es7-plugin-1.1.7.tgz#f2ee1f3228a90eead1245f9ab1922eb2e71d336b" integrity sha512-7D+8kscFMf6F2t+8ZRYmv82CncDZETsaZ4dEl5lh3qQez7FVABk2Vz616SAbnIq1PbNsLVaZjl2oSkk5BWAKng== -acorn-globals@^1.0.4: - version "1.0.9" - resolved "https://registry.npmjs.org/acorn-globals/-/acorn-globals-1.0.9.tgz#55bb5e98691507b74579d0513413217c380c54cf" - integrity sha512-j3/4pkfih8W4NK22gxVSXcEonTpAHOHh0hu5BoZrKcOsW/4oBPxTi4Yk3SAj+FhC1f3+bRTkXdm4019gw1vg9g== - dependencies: - acorn "^2.1.0" - acorn-globals@^4.3.0: version "4.3.4" resolved "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz#9fa1926addc11c97308c4e66d7add0d40c3272e7" @@ -851,7 +848,7 @@ acorn-import-assertions@^1.9.0: resolved "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz#507276249d684797c84e0734ef84860334cfb1ac" integrity sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA== -acorn-jsx@^5.2.0, acorn-jsx@^5.3.2: +acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== @@ -866,11 +863,6 @@ acorn-walk@^8.0.0, acorn-walk@^8.1.1: resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz#7703af9415f1b6db9315d6895503862e231d34aa" integrity sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A== -acorn@^2.1.0, acorn@^2.4.0: - version "2.7.0" - resolved "https://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz#ab6e7d9d886aaca8b085bc3312b79a198433f0e7" - integrity sha512-pXK8ez/pVjqFdAgBkF1YPVRacuLQ9EXBKaKWaeh58WNfMkCmZhOZzu+NtKSPD5PHmCCHheQ5cD29qM1K4QTxIg== - acorn@^5.0.0: version "5.7.4" resolved "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz#3e8d8a9947d0599a1796d10225d7432f4a4acf5e" @@ -881,11 +873,6 @@ acorn@^6.0.1, acorn@^6.0.4: resolved "https://registry.npmjs.org/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== -acorn@^7.1.1: - version "7.4.1" - resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa" - integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== - acorn@^8.0.4, acorn@^8.4.1, acorn@^8.7.1, acorn@^8.8.2, acorn@^8.9.0: version "8.11.3" resolved "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" @@ -903,7 +890,7 @@ ajv-keywords@^3.5.2: resolved "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== -ajv@^6.10.0, ajv@^6.10.2, ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5: +ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5: version "6.12.6" resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -937,13 +924,6 @@ ansi-cyan@^0.1.1: dependencies: ansi-wrap "0.1.0" -ansi-escapes@^4.2.1: - version "4.3.2" - resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" - integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== - dependencies: - type-fest "^0.21.3" - ansi-gray@^0.1.1: version "0.1.1" resolved "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz#2962cf54ec9792c48510a3deb524436861ef7251" @@ -968,11 +948,6 @@ ansi-regex@^3.0.0: resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz#123d6479e92ad45ad897d4054e3c7ca7db4944e1" integrity sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw== -ansi-regex@^4.1.0: - version "4.1.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" - integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== - ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" @@ -983,12 +958,12 @@ ansi-regex@^6.0.1: resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== -ansi-styles@^2.2.1: - version "2.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" - integrity sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA== +ansi-sequence-parser@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ansi-sequence-parser/-/ansi-sequence-parser-1.1.1.tgz#e0aa1cdcbc8f8bb0b5bca625aac41f5f056973cf" + integrity sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg== -ansi-styles@^3.2.0, ansi-styles@^3.2.1: +ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== @@ -1048,18 +1023,16 @@ archy@^1.0.0: resolved "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" integrity sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw== +are-docs-informative@^0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/are-docs-informative/-/are-docs-informative-0.0.2.tgz#387f0e93f5d45280373d387a59d34c96db321963" + integrity sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig== + arg@^4.1.0: version "4.1.3" resolved "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - argparse@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" @@ -1237,11 +1210,6 @@ assign-symbols@^1.0.0: resolved "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" integrity sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw== -astral-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9" - integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg== - async-done@^1.2.0, async-done@^1.2.2: version "1.3.2" resolved "https://registry.npmjs.org/async-done/-/async-done-1.3.2.tgz#5e15aa729962a4b07414f528a88cdf18e0b290a2" @@ -1311,86 +1279,6 @@ aws4@^1.8.0: resolved "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz#ce1c9d143389679e253b314241ea9aa5cec980d3" integrity sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg== -babel-code-frame@^6.26.0: - version "6.26.0" - resolved "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" - integrity sha512-XqYMR2dfdGMW+hd0IUZ2PwK+fGeFkOxZJ0wY+JaQAHzt1Zx8LcvpiZD2NiGkEG8qx0CfkAOr5xt76d1e8vG90g== - dependencies: - chalk "^1.1.3" - esutils "^2.0.2" - js-tokens "^3.0.2" - -babel-generator@6.11.4: - version "6.11.4" - resolved "https://registry.npmjs.org/babel-generator/-/babel-generator-6.11.4.tgz#14f6933abb20c62666d27e3b7b9f5b9dc0712a9a" - integrity sha512-JFBWXdE89s4V3E8kZroEEsnQF2A4/+55IzciGjnAATXj7HTMSum3SrW7QRYGSDLWTTQF+hhD3BmC2UFGgtM0Yw== - dependencies: - babel-messages "^6.8.0" - babel-runtime "^6.9.0" - babel-types "^6.10.2" - detect-indent "^3.0.1" - lodash "^4.2.0" - source-map "^0.5.0" - -babel-generator@6.26.1: - version "6.26.1" - resolved "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz#1844408d3b8f0d35a404ea7ac180f087a601bd90" - integrity sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA== - dependencies: - babel-messages "^6.23.0" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - detect-indent "^4.0.0" - jsesc "^1.3.0" - lodash "^4.17.4" - source-map "^0.5.7" - trim-right "^1.0.1" - -babel-messages@^6.23.0, babel-messages@^6.8.0: - version "6.23.0" - resolved "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" - integrity sha512-Bl3ZiA+LjqaMtNYopA9TYE9HP1tQ+E5dLxE0XrAzcIJeK2UqF0/EaqXwBn9esd4UmTfEab+P+UYQ1GnioFIb/w== - dependencies: - babel-runtime "^6.22.0" - -babel-runtime@^6.22.0, babel-runtime@^6.26.0, babel-runtime@^6.9.0: - version "6.26.0" - resolved "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe" - integrity sha512-ITKNuq2wKlW1fJg9sSW52eepoYgZBggvOAHC0u/CYu/qxQ9EVzThCgR69BnSXLHjy2f7SY5zaQ4yt7H9ZVxY2g== - dependencies: - core-js "^2.4.0" - regenerator-runtime "^0.11.0" - -babel-traverse@6.26.0: - version "6.26.0" - resolved "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" - integrity sha512-iSxeXx7apsjCHe9c7n8VtRXGzI2Bk1rBSOJgCCjfyXb6v1aCqE1KSEpq/8SXuVN8Ka/Rh1WDTF0MDzkvTA4MIA== - dependencies: - babel-code-frame "^6.26.0" - babel-messages "^6.23.0" - babel-runtime "^6.26.0" - babel-types "^6.26.0" - babylon "^6.18.0" - debug "^2.6.8" - globals "^9.18.0" - invariant "^2.2.2" - lodash "^4.17.4" - -babel-types@^6.10.2, babel-types@^6.26.0: - version "6.26.0" - resolved "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" - integrity sha512-zhe3V/26rCWsEZK8kZN+HaQj5yQ1CilTObixFzKW1UWjqG7618Twz6YEsCnjfg5gBcJh02DrpCkS9h98ZqDY+g== - dependencies: - babel-runtime "^6.26.0" - esutils "^2.0.2" - lodash "^4.17.4" - to-fast-properties "^1.0.3" - -babylon@6.18.0, babylon@^6.18.0: - version "6.18.0" - resolved "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" - integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ== - bach@^1.0.0: version "1.2.0" resolved "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz#4b3ce96bf27134f79a1b414a51c14e34c3bd9880" @@ -1481,11 +1369,6 @@ body-parser@^1.19.0: type-is "~1.6.18" unpipe "1.0.0" -boolbase@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" - integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww== - bootstrap-icons@^1.10.5: version "1.11.3" resolved "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.11.3.tgz#03f9cb754ec005c52f9ee616e2e84a82cab3084b" @@ -1602,6 +1485,11 @@ buffer-from@^1.0.0: resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== +builtin-modules@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6" + integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw== + bytes@3.1.2: version "3.1.2" resolved "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" @@ -1676,17 +1564,6 @@ chai@^4.3.7: pathval "^1.1.1" type-detect "^4.0.8" -chalk@^1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" - integrity sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A== - dependencies: - ansi-styles "^2.2.1" - escape-string-regexp "^1.0.2" - has-ansi "^2.0.0" - strip-ansi "^3.0.0" - supports-color "^2.0.0" - chalk@^2.0.1, chalk@^2.1.0, chalk@^2.4.2: version "2.4.2" resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -1709,11 +1586,6 @@ chance@^1.1.9: resolved "https://registry.npmjs.org/chance/-/chance-1.1.11.tgz#78e10e1f9220a5bbc60a83e3f28a5d8558d84d1b" integrity sha512-kqTg3WWywappJPqtgrdvbA380VoXO2eu9VCV895JgbyHsaErXdyHK9LOZ911OvAk6L0obK7kDk9CGs8+oBawVA== -chardet@^0.7.0: - version "0.7.0" - resolved "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" - integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== - check-error@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz#a6502e4312a7ee969f646e83bb3ddd56281bd694" @@ -1721,53 +1593,6 @@ check-error@^1.0.3: dependencies: get-func-name "^2.0.2" -cheerio@0.20.0: - version "0.20.0" - resolved "https://registry.npmjs.org/cheerio/-/cheerio-0.20.0.tgz#5c710f2bab95653272842ba01c6ea61b3545ec35" - integrity sha512-e5jCTzJc28MWkrLLjB1mu3ks7rDQJLC5y/JMdQkOAEX/dmJk62rC6Xae1yvOO4xyCxLpzcth3jIZ7nypmjQ/0w== - dependencies: - css-select "~1.2.0" - dom-serializer "~0.1.0" - entities "~1.1.1" - htmlparser2 "~3.8.1" - lodash "^4.1.0" - optionalDependencies: - jsdom "^7.0.2" - -cheerio@0.22.0: - version "0.22.0" - resolved "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz#a9baa860a3f9b595a6b81b1a86873121ed3a269e" - integrity sha512-8/MzidM6G/TgRelkzDG13y3Y9LxBjCb+8yOEZ9+wwq5gVF2w2pV0wmHvjfT0RvuxGyR7UEuK36r+yYMbT4uKgA== - dependencies: - css-select "~1.2.0" - dom-serializer "~0.1.0" - entities "~1.1.1" - htmlparser2 "^3.9.1" - lodash.assignin "^4.0.9" - lodash.bind "^4.1.4" - lodash.defaults "^4.0.1" - lodash.filter "^4.4.0" - lodash.flatten "^4.2.0" - lodash.foreach "^4.3.0" - lodash.map "^4.4.0" - lodash.merge "^4.4.0" - lodash.pick "^4.2.1" - lodash.reduce "^4.4.0" - lodash.reject "^4.4.0" - lodash.some "^4.4.0" - -cheerio@1.0.0-rc.2: - version "1.0.0-rc.2" - resolved "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.2.tgz#4b9f53a81b27e4d5dac31c0ffd0cfa03cc6830db" - integrity sha512-9LDHQy1jHc/eXMzPN6/oah9Qba4CjdKECC7YYEE/2zge/tsGwt19NQp5NFdfd5Lx6TZlyC5SXNQkG41P9r6XDg== - dependencies: - css-select "~1.2.0" - dom-serializer "~0.1.0" - entities "~1.1.1" - htmlparser2 "^3.9.1" - lodash "^4.15.0" - parse5 "^3.0.1" - chokidar@3.5.3: version "3.5.3" resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" @@ -1839,18 +1664,6 @@ clean-css@4.2.3: dependencies: source-map "~0.6.0" -cli-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" - integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== - dependencies: - restore-cursor "^3.1.0" - -cli-width@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" - integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== - cliui@^3.2.0: version "3.2.0" resolved "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" @@ -1948,16 +1761,6 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-logger@0.0.3: - version "0.0.3" - resolved "https://registry.npmjs.org/color-logger/-/color-logger-0.0.3.tgz#d9b22dd1d973e166b18bf313f9f481bba4df2018" - integrity sha512-s4oriek7VTdSmDbS5chJhNui3uUzlk/mU39V4HnOUv0KphRXpIj73lq4wY5f8l/x+WtHUhiV+FCzsrNO1w6REA== - -color-logger@0.0.6: - version "0.0.6" - resolved "https://registry.npmjs.org/color-logger/-/color-logger-0.0.6.tgz#e56245ef29822657110c7cb75a9cd786cb69ed1b" - integrity sha512-0iBj3eHRYnor8EJi3oQ1kixbr7B2Sbw1InxjsYZxS+q2H+Ii69m3ARYSJeYIqmf/QRtFhWnR1v97wp8N7ABubw== - color-name@1.1.3: version "1.1.3" resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" @@ -2000,6 +1803,11 @@ commander@^7.2.0: resolved "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== +comment-parser@1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.4.1.tgz#bdafead37961ac079be11eb7ec65c4d021eaf9cc" + integrity sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg== + compare-versions@^6.0.0-rc.2: version "6.1.0" resolved "https://registry.npmjs.org/compare-versions/-/compare-versions-6.1.0.tgz#3f2131e3ae93577df111dba133e6db876ffe127a" @@ -2100,7 +1908,7 @@ copy-props@^2.0.1: each-props "^1.3.2" is-plain-object "^5.0.0" -core-js@^2.0.0, core-js@^2.4.0: +core-js@^2.0.0: version "2.6.12" resolved "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz#d9333dfa7b065e347cc5682219d6f690859cc2ec" integrity sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ== @@ -2154,17 +1962,6 @@ cross-spawn@^5.0.1: shebang-command "^1.2.0" which "^1.2.9" -cross-spawn@^6.0.5: - version "6.0.5" - resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" - integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== - dependencies: - nice-try "^1.0.4" - path-key "^2.0.1" - semver "^5.5.0" - shebang-command "^1.2.0" - which "^1.2.9" - cross-spawn@^7.0.0, cross-spawn@^7.0.2, cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" @@ -2181,33 +1978,11 @@ crossvent@1.5.5: dependencies: custom-event "^1.0.0" -css-select@~1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" - integrity sha512-dUQOBoqdR7QwV90WysXPLXG5LO7nhYBgiWVfxF80DKPF8zx1t/pUd2FYy73emg3zrjtM6dzmYgbHKfV2rxiHQA== - dependencies: - boolbase "~1.0.0" - css-what "2.1" - domutils "1.5.1" - nth-check "~1.0.1" - -css-what@2.1: - version "2.1.3" - resolved "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2" - integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg== - -cssom@0.3.x, "cssom@>= 0.3.0 < 0.4.0", cssom@^0.3.4: +cssom@0.3.x, cssom@^0.3.4: version "0.3.8" resolved "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== -"cssstyle@>= 0.2.29 < 0.3.0": - version "0.2.37" - resolved "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.37.tgz#541097234cb2513c83ceed3acddc27ff27987d54" - integrity sha512-FUpKc+1FNBsHUr9IsfSGCovr8VuGOiiuzlgCyppKBjJi2jYTOFLN3oiiNRMIvYqbFzF38mqKj4BgcevzU5/kIA== - dependencies: - cssom "0.3.x" - cssstyle@^1.1.1: version "1.4.0" resolved "https://registry.npmjs.org/cssstyle/-/cssstyle-1.4.0.tgz#9d31328229d3c565c61e586b02041a28fccdccf1" @@ -2302,14 +2077,14 @@ debounce@^1.2.1: resolved "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5" integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug== -debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: +debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9: version "2.6.9" resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" -debug@4, debug@4.3.4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2, debug@~4.3.4: +debug@4, debug@4.3.4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2, debug@~4.3.4: version "4.3.4" resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -2425,22 +2200,6 @@ detect-file@^1.0.0: resolved "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" integrity sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q== -detect-indent@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-3.0.1.tgz#9dc5e5ddbceef8325764b9451b02bc6d54084f75" - integrity sha512-xo3WP66SNbr1Eim85s/qyH0ZL8PQUwp86HWm0S1l8WnJ/zjT6T3w1nwNA0yOZeuvOemupEYvpvF6BIdYRuERJQ== - dependencies: - get-stdin "^4.0.1" - minimist "^1.1.0" - repeating "^1.1.0" - -detect-indent@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" - integrity sha512-BDKtmHlOzwI7iRuEkhzsnPoi5ypEhWAJB5RvHWe1kMr06js3uK5B3734i3ui5Yd+wOJV1cpE4JnivPD283GU/A== - dependencies: - repeating "^2.0.0" - di@^0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/di/-/di-0.0.1.tgz#806649326ceaa7caa3306d75d985ea2748ba913c" @@ -2519,22 +2278,6 @@ dom-serialize@^2.2.1: extend "^3.0.0" void-elements "^2.0.0" -dom-serializer@0: - version "0.2.2" - resolved "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz#1afb81f533717175d478655debc5e332d9f9bb51" - integrity sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g== - dependencies: - domelementtype "^2.0.1" - entities "^2.0.0" - -dom-serializer@~0.1.0: - version "0.1.1" - resolved "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz#1ec4059e284babed36eec2941d4a970a189ce7c0" - integrity sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA== - dependencies: - domelementtype "^1.3.0" - entities "^1.1.1" - dom-set@^1.0.1: version "1.1.1" resolved "https://registry.npmjs.org/dom-set/-/dom-set-1.1.1.tgz#5c2c610ee4839b520ed5f98ddbcbe314c0fa954a" @@ -2549,16 +2292,6 @@ dom-walk@^0.1.0: resolved "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz#0c548bef048f4d1f2a97249002236060daa3fd84" integrity sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w== -domelementtype@1, domelementtype@^1.3.0, domelementtype@^1.3.1: - version "1.3.1" - resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f" - integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w== - -domelementtype@^2.0.1: - version "2.3.0" - resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" - integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== - domexception@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90" @@ -2573,41 +2306,11 @@ domexception@^4.0.0: dependencies: webidl-conversions "^7.0.0" -domhandler@2.3: - version "2.3.0" - resolved "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz#2de59a0822d5027fabff6f032c2b25a2a8abe738" - integrity sha512-q9bUwjfp7Eif8jWxxxPSykdRZAb6GkguBGSgvvCrhI9wB71W2K/Kvv4E61CF/mcCfnVJDeDWx/Vb/uAqbDj6UQ== - dependencies: - domelementtype "1" - -domhandler@^2.3.0: - version "2.4.2" - resolved "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803" - integrity sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA== - dependencies: - domelementtype "1" - dompurify@^3.0.6, dompurify@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/dompurify/-/dompurify-3.1.0.tgz#8c6b9fe986969a33aa4686bd829cbe8e14dd9445" integrity sha512-yoU4rhgPKCo+p5UrWWWNKiIq+ToGqmVVhk0PmMYBK4kRsR3/qhemNFL8f6CFmBd4gMwm3F4T7HBoydP5uY07fA== -domutils@1.5, domutils@1.5.1: - version "1.5.1" - resolved "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" - integrity sha512-gSu5Oi/I+3wDENBsOWBiRK1eoGxcywYSqg3rR960/+EfY0CF4EX1VPkgHOZ3WiS/Jg2DtliF6BhWcHlfpYUcGw== - dependencies: - dom-serializer "0" - domelementtype "1" - -domutils@^1.5.1: - version "1.7.0" - resolved "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a" - integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg== - dependencies: - dom-serializer "0" - domelementtype "1" - downloadjs@^1.4.7: version "1.4.7" resolved "https://registry.npmjs.org/downloadjs/-/downloadjs-1.4.7.tgz#f69f96f940e0d0553dac291139865a3cd0101e3c" @@ -2685,11 +2388,6 @@ electron-to-chromium@^1.4.668: resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.736.tgz#ecb4348f4d5c70fb1e31c347e5bad6b751066416" integrity sha512-Rer6wc3ynLelKNM4lOCg7/zPQj8tPOCB2hzD32PX9wd3hgRRi9MxEbmkFCokzcEhRVMiOVLjnL9ig9cefJ+6+Q== -emoji-regex@^7.0.1: - version "7.0.3" - resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" - integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== - emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" @@ -2767,21 +2465,6 @@ ent@~2.2.0: resolved "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d" integrity sha512-GHrMyVZQWvTIdDtpiEXdHZnFQKzeO09apj8Cbl4pKWy4i0Oprcq17usfDt5aO63swf0JOeMWjWQE/LzgSRuWpA== -entities@1.0: - version "1.0.0" - resolved "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz#b2987aa3821347fcde642b24fdfc9e4fb712bf26" - integrity sha512-LbLqfXgJMmy81t+7c14mnulFHJ170cM6E+0vMXR9k/ZiZwgX8i5pNgjTCX3SO4VeUsFLV+8InixoretwU+MjBQ== - -entities@^1.1.1, entities@~1.1.1: - version "1.1.2" - resolved "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56" - integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w== - -entities@^2.0.0: - version "2.2.0" - resolved "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" - integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== - entities@^4.4.0: version "4.5.0" resolved "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" @@ -2947,7 +2630,7 @@ escalade@^3.1.1: resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== -escape-html@1.0.3, escape-html@~1.0.3: +escape-html@~1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== @@ -2957,7 +2640,7 @@ escape-string-regexp@4.0.0, escape-string-regexp@^4.0.0: resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.3, escape-string-regexp@^1.0.5: +escape-string-regexp@^1.0.3, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== @@ -2967,7 +2650,7 @@ escape-string-regexp@^5.0.0: resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz#4683126b500b61762f2dbebace1806e8be31b1c8" integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw== -escodegen@^1.11.0, escodegen@^1.6.1: +escodegen@^1.11.0: version "1.14.3" resolved "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== @@ -2979,118 +2662,22 @@ escodegen@^1.11.0, escodegen@^1.6.1: optionalDependencies: source-map "~0.6.1" -esdoc-accessor-plugin@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/esdoc-accessor-plugin/-/esdoc-accessor-plugin-1.0.0.tgz#791ba4872e6c403515ce749b1348d6f0293ad9eb" - integrity sha512-s9mNmdHGOyQOaOUXNHPz38Y8clm6dR8/fa9DPGzuRYmIN+Lv0NVnpPAcHb5XrfC23/Mz3IUwD8h798f5Ai4rbA== - -esdoc-brand-plugin@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/esdoc-brand-plugin/-/esdoc-brand-plugin-1.0.1.tgz#7c0e1ae90e84c30b2d3369d3a6449f9dc9f8d511" - integrity sha512-Yv9j3M7qk5PSLmSeD6MbPsfIsEf8K43EdH8qZpE/GZwnJCRVmDPrZJ1cLDj/fPu6P35YqgcEaJK4E2NL/CKA7g== +eslint-plugin-jsdoc@^48.2.3: + version "48.2.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.2.3.tgz#0188d17c7a4aa7185416556589e71a954b343ecd" + integrity sha512-r9DMAmFs66VNvNqRLLjHejdnJtILrt3xGi+Qx0op0oRfFGVpOR1Hb3BC++MacseHx93d8SKYPhyrC9BS7Os2QA== dependencies: - cheerio "0.22.0" - -esdoc-coverage-plugin@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/esdoc-coverage-plugin/-/esdoc-coverage-plugin-1.1.0.tgz#3869869cd7f87891f972625787695a299aece45c" - integrity sha512-M+94/Y+eoM08V3teiJIYpJ5HF13jH4cC9LQZrjmA91mlAqCHtNzelHF9ZdWofoOFYFRNpllFsXTFsJgwVa000A== - -esdoc-ecmascript-proposal-plugin@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/esdoc-ecmascript-proposal-plugin/-/esdoc-ecmascript-proposal-plugin-1.0.0.tgz#390dc5656ba8a2830e39dba3570d79138df2ffd9" - integrity sha512-PuaU/O8d+Sb0J6qQdyhmy74h/2cp/2kqsvPuoCiK+50Rw54nlGqXxvWNaaNikS5qntE0FfssnwZtUPa6q4RiXg== - -esdoc-external-ecmascript-plugin@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/esdoc-external-ecmascript-plugin/-/esdoc-external-ecmascript-plugin-1.0.0.tgz#78f565d4a0c5185ac63152614dce1fe1a86688db" - integrity sha512-ASj7lhfZpzI01xd4XqB4HN+zNKwnhdaN/OIp/CTnUiLIErMOeUqzV9z/dcnUUeDY3NSwPCH1pUNATVwznspmHw== - dependencies: - fs-extra "1.0.0" - -esdoc-integrate-manual-plugin@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/esdoc-integrate-manual-plugin/-/esdoc-integrate-manual-plugin-1.0.0.tgz#1854a6aa1c081035d7c8c51e3bdd4fb65aa4711c" - integrity sha512-+XcW8xRtuFVFadoVLIOj6kzX4uqtAEB5UoR7AA5g46StxLghZZ6RLrRQSERUTIc3VX9v47lOMKEaQvQfanv3+A== - -esdoc-integrate-test-plugin@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/esdoc-integrate-test-plugin/-/esdoc-integrate-test-plugin-1.0.0.tgz#e2d0d00090f7f0c35e5d2f2c033327a79e53e409" - integrity sha512-WRbkbnbWnzF4RdmcoJLYZvhod7jLVUYWU2ZAojYjK+GiqSgy2yjGi7PxckeGF0LtpCuqqKat3PRdUNEMo6Nf3A== - -esdoc-lint-plugin@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/esdoc-lint-plugin/-/esdoc-lint-plugin-1.0.2.tgz#4962930c6dc5b25d80cf6eff1b0f3c24609077f7" - integrity sha512-24AYqD2WbZI9We02I7/6dzAa7yUliRTFUaJCZAcYJMQicJT5gUrNFVaI8XmWEN/mhF3szIn1uZBNWeLul4CmNw== - -esdoc-publish-html-plugin@^1.0.0: - version "1.1.2" - resolved "https://registry.npmjs.org/esdoc-publish-html-plugin/-/esdoc-publish-html-plugin-1.1.2.tgz#bdece7bc7a0a3e419933503252db7a6772879dab" - integrity sha512-hG1fZmTcEp3P/Hv/qKiMdG1qSp8MjnVZMMkxL5P5ry7I2sX0HQ4P9lt2lms+90Lt0r340HHhSuVx107UL7dphg== - dependencies: - babel-generator "6.11.4" - cheerio "0.22.0" - escape-html "1.0.3" - fs-extra "1.0.0" - ice-cap "0.0.4" - marked "0.3.19" - taffydb "2.7.2" - -esdoc-standard-plugin@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/esdoc-standard-plugin/-/esdoc-standard-plugin-1.0.0.tgz#661201cac7ef868924902446fdac1527253c5d4d" - integrity sha512-IDEG9NV/MF5Bi2TdKPqQ3GHfDkgqYhk2iyvBNX+XcNKYmXm9zxtXVS459WAmiTZuYpDLtDGbulQdJ1t4ud57mw== - dependencies: - esdoc-accessor-plugin "^1.0.0" - esdoc-brand-plugin "^1.0.0" - esdoc-coverage-plugin "^1.0.0" - esdoc-external-ecmascript-plugin "^1.0.0" - esdoc-integrate-manual-plugin "^1.0.0" - esdoc-integrate-test-plugin "^1.0.0" - esdoc-lint-plugin "^1.0.0" - esdoc-publish-html-plugin "^1.0.0" - esdoc-type-inference-plugin "^1.0.0" - esdoc-undocumented-identifier-plugin "^1.0.0" - esdoc-unexported-identifier-plugin "^1.0.0" - -esdoc-type-inference-plugin@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/esdoc-type-inference-plugin/-/esdoc-type-inference-plugin-1.0.2.tgz#916e3f756de1d81d9c0dbe1c008e8dafd322cfaf" - integrity sha512-tMIcEHNe1uhUGA7lT1UTWc9hs2dzthnTgmqXpmeUhurk7fL2tinvoH+IVvG/sLROzwOGZQS9zW/F9KWnpMzLIQ== - -esdoc-undocumented-identifier-plugin@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/esdoc-undocumented-identifier-plugin/-/esdoc-undocumented-identifier-plugin-1.0.0.tgz#82e05d371c32d12871140f1d5c81ec99fd9cc2c8" - integrity sha512-T0hQc0ec1+pUJPDBoJ2SxEv7uX9VD7Q9+7UAGnDZ5R2l2JYa3WY7cawyqfbMHVtLgvqH0eMBpxdfRsQvAWzj4Q== - -esdoc-unexported-identifier-plugin@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/esdoc-unexported-identifier-plugin/-/esdoc-unexported-identifier-plugin-1.0.0.tgz#1f9874c6a7c2bebf9ad397c3ceb75c9c69dabab1" - integrity sha512-PRdMLWHWdy9PwxzYDG2clhta9H7yHDpGCBIHxSw9R7TFK6ZYuPK1fUbURIzIxcdQhzt1PX9Cn6Cak2824K0+Ng== - -esdoc@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/esdoc/-/esdoc-1.1.0.tgz#07d40ebf791764cd537929c29111e20a857624f3" - integrity sha512-vsUcp52XJkOWg9m1vDYplGZN2iDzvmjDL5M/Mp8qkoDG3p2s0yIQCIjKR5wfPBaM3eV14a6zhQNYiNTCVzPnxA== - dependencies: - babel-generator "6.26.1" - babel-traverse "6.26.0" - babylon "6.18.0" - cheerio "1.0.0-rc.2" - color-logger "0.0.6" - escape-html "1.0.3" - fs-extra "5.0.0" - ice-cap "0.0.4" - marked "0.3.19" - minimist "1.2.0" - taffydb "2.7.3" - -eslint-config-formio@^1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/eslint-config-formio/-/eslint-config-formio-1.1.4.tgz#64082979bdc8166445a463884998c7e1ee3b7de5" - integrity sha512-8V3cbflYi53i9QyWpl1MffkrSM/uz3tRQ86N+5K4WAa7qGtUeo9hDB5+ZrsfxT0nfnwqVf/1d5CgzUKH2EuKqw== + "@es-joy/jsdoccomment" "~0.42.0" + are-docs-informative "^0.0.2" + comment-parser "1.4.1" + debug "^4.3.4" + escape-string-regexp "^4.0.0" + esquery "^1.5.0" + is-builtin-module "^3.2.1" + semver "^7.6.0" + spdx-expression-parse "^4.0.0" -eslint-scope@5.1.1, eslint-scope@^5.0.0: +eslint-scope@5.1.1: version "5.1.1" resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== @@ -3106,66 +2693,11 @@ eslint-scope@^7.2.2: esrecurse "^4.3.0" estraverse "^5.2.0" -eslint-utils@^1.4.3: - version "1.4.3" - resolved "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz#74fec7c54d0776b6f67e0251040b5806564e981f" - integrity sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q== - dependencies: - eslint-visitor-keys "^1.1.0" - -eslint-visitor-keys@^1.1.0: - version "1.3.0" - resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e" - integrity sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ== - eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: version "3.4.3" resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== -eslint@^6.0.0: - version "6.8.0" - resolved "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz#62262d6729739f9275723824302fb227c8c93ffb" - integrity sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig== - dependencies: - "@babel/code-frame" "^7.0.0" - ajv "^6.10.0" - chalk "^2.1.0" - cross-spawn "^6.0.5" - debug "^4.0.1" - doctrine "^3.0.0" - eslint-scope "^5.0.0" - eslint-utils "^1.4.3" - eslint-visitor-keys "^1.1.0" - espree "^6.1.2" - esquery "^1.0.1" - esutils "^2.0.2" - file-entry-cache "^5.0.1" - functional-red-black-tree "^1.0.1" - glob-parent "^5.0.0" - globals "^12.1.0" - ignore "^4.0.6" - import-fresh "^3.0.0" - imurmurhash "^0.1.4" - inquirer "^7.0.0" - is-glob "^4.0.0" - js-yaml "^3.13.1" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.3.0" - lodash "^4.17.14" - minimatch "^3.0.4" - mkdirp "^0.5.1" - natural-compare "^1.4.0" - optionator "^0.8.3" - progress "^2.0.0" - regexpp "^2.0.1" - semver "^6.1.2" - strip-ansi "^5.2.0" - strip-json-comments "^3.0.1" - table "^5.2.3" - text-table "^0.2.0" - v8-compile-cache "^2.0.3" - eslint@^8.57.0: version "8.57.0" resolved "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz#c786a6fd0e0b68941aaf624596fb987089195668" @@ -3220,15 +2752,6 @@ esniff@^2.0.1: event-emitter "^0.3.5" type "^2.7.2" -espree@^6.1.2: - version "6.2.1" - resolved "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz#77fc72e1fd744a2052c20f38a5b575832e82734a" - integrity sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw== - dependencies: - acorn "^7.1.1" - acorn-jsx "^5.2.0" - eslint-visitor-keys "^1.1.0" - espree@^9.6.0, espree@^9.6.1: version "9.6.1" resolved "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" @@ -3238,7 +2761,7 @@ espree@^9.6.0, espree@^9.6.1: acorn-jsx "^5.3.2" eslint-visitor-keys "^3.4.1" -esprima@^4.0.0, esprima@^4.0.1: +esprima@^4.0.1: version "4.0.1" resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== @@ -3250,7 +2773,7 @@ espurify@^1.6.0: dependencies: core-js "^2.0.0" -esquery@^1.0.1, esquery@^1.4.2: +esquery@^1.4.2, esquery@^1.5.0: version "1.5.0" resolved "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== @@ -3370,15 +2893,6 @@ extend@^3.0.0, extend@~3.0.2: resolved "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== -external-editor@^3.0.3: - version "3.1.0" - resolved "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" - integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== - dependencies: - chardet "^0.7.0" - iconv-lite "^0.4.24" - tmp "^0.0.33" - extglob@^0.3.1: version "0.3.2" resolved "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" @@ -3522,20 +3036,6 @@ fetch-ponyfill@^7.1.0: dependencies: node-fetch "~2.6.1" -figures@^3.0.0: - version "3.2.0" - resolved "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" - integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== - dependencies: - escape-string-regexp "^1.0.5" - -file-entry-cache@^5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c" - integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g== - dependencies: - flat-cache "^2.0.1" - file-entry-cache@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" @@ -3669,15 +3169,6 @@ flagged-respawn@^1.0.0: resolved "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz#e7de6f1279ddd9ca9aac8a5971d618606b3aab41" integrity sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q== -flat-cache@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0" - integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA== - dependencies: - flatted "^2.0.0" - rimraf "2.6.3" - write "1.0.3" - flat-cache@^3.0.4: version "3.2.0" resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" @@ -3697,11 +3188,6 @@ flatpickr@^4.6.13: resolved "https://registry.npmjs.org/flatpickr/-/flatpickr-4.6.13.tgz#8a029548187fd6e0d670908471e43abe9ad18d94" integrity sha512-97PMG/aywoYpB4IvbvUJi0RQi8vearvU0oov1WW3k0WZPBMrTQVqekSX5CjSG/M4Q3i6A/0FKXC7RyAoAUUSPw== -flatted@^2.0.0: - version "2.0.2" - resolved "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138" - integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA== - flatted@^3.2.7, flatted@^3.2.9: version "3.3.1" resolved "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a" @@ -3789,7 +3275,7 @@ fragment-cache@^0.2.1: dependencies: map-cache "^0.2.2" -fs-extra@1.0.0, fs-extra@^1.0.0: +fs-extra@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-1.0.0.tgz#cd3ce5f7e7cb6145883fcae3191e9877f8587950" integrity sha512-VerQV6vEKuhDWD2HGOybV6v5I73syoc/cXAbKlgTC7M/oFVEtklWlp9QH2Ijw3IaWDOQcMkldSPa7zXy79Z/UQ== @@ -3798,15 +3284,6 @@ fs-extra@1.0.0, fs-extra@^1.0.0: jsonfile "^2.1.0" klaw "^1.0.0" -fs-extra@5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-5.0.0.tgz#414d0110cdd06705734d055652c5411260c31abd" - integrity sha512-66Pm4RYbjzdyeuqudYqhFiNBbCIuI9kgRqLPSHIlXHidW8NIQtVdkM1yeZ4lXwuhbTETv3EUGMNHAAw6hiundQ== - dependencies: - graceful-fs "^4.1.2" - jsonfile "^4.0.0" - universalify "^0.1.0" - fs-extra@^8.1.0: version "8.1.0" resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" @@ -3857,11 +3334,6 @@ function.prototype.name@^1.1.6: es-abstract "^1.22.1" functions-have-names "^1.2.3" -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== - functions-have-names@^1.2.3: version "1.2.3" resolved "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" @@ -3903,11 +3375,6 @@ get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@ has-symbols "^1.0.3" hasown "^2.0.0" -get-stdin@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" - integrity sha512-F5aQMywwJ2n85s4hJPTT9RPxGmubonuB10MNYo17/xph174n2MIR33HRguhzVag10O/npM7SPk73LMZNP+FaWw== - get-symbol-description@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz#533744d5aa20aca4e079c8e5daf7fd44202821f5" @@ -3952,7 +3419,7 @@ glob-parent@^3.0.1, glob-parent@^3.1.0: is-glob "^3.1.0" path-dirname "^1.0.0" -glob-parent@^5.0.0, glob-parent@^5.1.2, glob-parent@~5.1.2: +glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== @@ -4067,13 +3534,6 @@ globals@^11.1.0: resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -globals@^12.1.0: - version "12.4.0" - resolved "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz#a18813576a41b00a24a97e7f815918c2e19925f8" - integrity sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg== - dependencies: - type-fest "^0.8.1" - globals@^13.19.0: version "13.24.0" resolved "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" @@ -4081,11 +3541,6 @@ globals@^13.19.0: dependencies: type-fest "^0.20.2" -globals@^9.18.0: - version "9.18.0" - resolved "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" - integrity sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ== - globalthis@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" @@ -4183,15 +3638,6 @@ gulp-concat@^2.6.1: through2 "^2.0.0" vinyl "^2.0.0" -gulp-eslint@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/gulp-eslint/-/gulp-eslint-6.0.0.tgz#7d402bb45f8a67652b868277011812057370a832" - integrity sha512-dCVPSh1sA+UVhn7JSQt7KEb4An2sQNbOdB3PA8UCfxsoPlAKjJHxYHGXdXC7eb+V1FAnilSFFqslPrq037l1ig== - dependencies: - eslint "^6.0.0" - fancy-log "^1.3.2" - plugin-error "^1.0.1" - gulp-filter@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/gulp-filter/-/gulp-filter-7.0.0.tgz#e0712f3e57b5d647f802a1880255cafb54abf158" @@ -4290,13 +3736,6 @@ har-validator@~5.1.3: ajv "^6.12.3" har-schema "^2.0.0" -has-ansi@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" - integrity sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg== - dependencies: - ansi-regex "^2.0.0" - has-bigints@^1.0.1, has-bigints@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" @@ -4423,29 +3862,6 @@ html-escaper@^2.0.2: resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== -htmlparser2@^3.9.1: - version "3.10.1" - resolved "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f" - integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ== - dependencies: - domelementtype "^1.3.1" - domhandler "^2.3.0" - domutils "^1.5.1" - entities "^1.1.1" - inherits "^2.0.1" - readable-stream "^3.1.1" - -htmlparser2@~3.8.1: - version "3.8.3" - resolved "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz#996c28b191516a8be86501a7d79757e5c70c1068" - integrity sha512-hBxEg3CYXe+rPIua8ETe7tmG3XDn9B0edOE/e9wH2nLczxzgdu0m0aNHY+5wFZiviLWLdANPJTssa92dMcXQ5Q== - dependencies: - domelementtype "1" - domhandler "2.3" - domutils "1.5" - entities "1.0" - readable-stream "1.1" - http-errors@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" @@ -4492,15 +3908,7 @@ https-proxy-agent@^5.0.1: agent-base "6" debug "4" -ice-cap@0.0.4: - version "0.0.4" - resolved "https://registry.npmjs.org/ice-cap/-/ice-cap-0.0.4.tgz#8a6d31ab4cac8d4b56de4fa946df3352561b6e18" - integrity sha512-39ZblYEKlqj7LHgLkUcVk7zcJp772lOVQAUhN6QyY88w8/4bn5SgDeU2020yzHosf+uKPuCFK1UQ36gyBNiraw== - dependencies: - cheerio "0.20.0" - color-logger "0.0.3" - -iconv-lite@0.4.24, iconv-lite@^0.4.24: +iconv-lite@0.4.24: version "0.4.24" resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -4519,11 +3927,6 @@ idb@^7.1.1: resolved "https://registry.npmjs.org/idb/-/idb-7.1.1.tgz#d910ded866d32c7ced9befc5bfdf36f572ced72b" integrity sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ== -ignore@^4.0.6: - version "4.0.6" - resolved "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - ignore@^5.2.0, ignore@^5.3.1: version "5.3.1" resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" @@ -4534,7 +3937,7 @@ immutable@^4.0.0: resolved "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz#f8b436e66d59f99760dc577f5c99a4fd2a5cc5a0" integrity sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw== -import-fresh@^3.0.0, import-fresh@^3.2.1: +import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== @@ -4568,7 +3971,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.3: version "2.0.4" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -4588,25 +3991,6 @@ inputmask@^5.0.9-beta.45: resolved "https://registry.npmjs.org/inputmask/-/inputmask-5.0.9-beta.62.tgz#e882904404e6038155492f939170820da89f3157" integrity sha512-8r2R5YEk6xEWgV6Sd8PwmMkFBF/9uGJipPYE01BAvZLFnK7oUKI9yaB74fHEc4525Y3lM69qk48oMq6jTN8cZQ== -inquirer@^7.0.0: - version "7.3.3" - resolved "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" - integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== - dependencies: - ansi-escapes "^4.2.1" - chalk "^4.1.0" - cli-cursor "^3.1.0" - cli-width "^3.0.0" - external-editor "^3.0.3" - figures "^3.0.0" - lodash "^4.17.19" - mute-stream "0.0.8" - run-async "^2.4.0" - rxjs "^6.6.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - through "^2.3.6" - internal-slot@^1.0.7: version "1.0.7" resolved "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz#c06dcca3ed874249881007b0a5523b172a190802" @@ -4626,13 +4010,6 @@ interpret@^3.1.1: resolved "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz#5be0ceed67ca79c6c4bc5cf0d7ee843dcea110c4" integrity sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ== -invariant@^2.2.2: - version "2.2.4" - resolved "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" - integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== - dependencies: - loose-envify "^1.0.0" - invert-kv@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" @@ -4705,6 +4082,13 @@ is-buffer@^1.1.5: resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== +is-builtin-module@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-3.2.1.tgz#f03271717d8654cfcaf07ab0463faa3571581169" + integrity sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A== + dependencies: + builtin-modules "^3.3.0" + is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: version "1.2.7" resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" @@ -4788,11 +4172,6 @@ is-extglob@^2.1.0, is-extglob@^2.1.1: resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== -is-finite@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3" - integrity sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w== - is-fullwidth-code-point@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" @@ -4800,11 +4179,6 @@ is-fullwidth-code-point@^1.0.0: dependencies: number-is-nan "^1.0.0" -is-fullwidth-code-point@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" - integrity sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w== - is-fullwidth-code-point@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" @@ -5006,11 +4380,6 @@ is-windows@^1.0.1, is-windows@^1.0.2: resolved "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" - integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== - isarray@1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" @@ -5100,16 +4469,11 @@ js-cookie@^3.0.5: resolved "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz#0b7e2fd0c01552c58ba86e0841f94dc2557dcdbc" integrity sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw== -"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: +js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== -js-tokens@^3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" - integrity sha512-RjTcuD4xjtthQkaWH7dFlH85L+QaVtSoOyGdZ3g6HFhS9dFNDfLyqgm2NFe2X6cQpeFmt0452FJjFG5UameExg== - js-yaml@4.1.0, js-yaml@^4.1.0: version "4.1.0" resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" @@ -5117,19 +4481,16 @@ js-yaml@4.1.0, js-yaml@^4.1.0: dependencies: argparse "^2.0.1" -js-yaml@^3.13.1: - version "3.14.1" - resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" - integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - jsbn@~0.1.0: version "0.1.1" resolved "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg== +jsdoc-type-pratt-parser@~4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz#136f0571a99c184d84ec84662c45c29ceff71114" + integrity sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ== + jsdom-global@^3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/jsdom-global/-/jsdom-global-3.0.2.tgz#6bd299c13b0c4626b2da2c0393cd4385d606acb9" @@ -5196,32 +4557,6 @@ jsdom@22.1.0: ws "^8.13.0" xml-name-validator "^4.0.0" -jsdom@^7.0.2: - version "7.2.2" - resolved "https://registry.npmjs.org/jsdom/-/jsdom-7.2.2.tgz#40b402770c2bda23469096bee91ab675e3b1fc6e" - integrity sha512-kYeYuos/pYp0V/V8VAoGnUc0va0UZjTjwCsldBFZNBrOi9Q5kUXrvsw6W5/lQllB7hKXBARC4HRk1Sfk4dPFtA== - dependencies: - abab "^1.0.0" - acorn "^2.4.0" - acorn-globals "^1.0.4" - cssom ">= 0.3.0 < 0.4.0" - cssstyle ">= 0.2.29 < 0.3.0" - escodegen "^1.6.1" - nwmatcher ">= 1.3.7 < 2.0.0" - parse5 "^1.5.1" - request "^2.55.0" - sax "^1.1.4" - symbol-tree ">= 3.1.0 < 4.0.0" - tough-cookie "^2.2.0" - webidl-conversions "^2.0.0" - whatwg-url-compat "~0.6.5" - xml-name-validator ">= 2.0.1 < 3.0.0" - -jsesc@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" - integrity sha512-Mke0DA0QjUWuJlhsE0ZPPhYiJkRap642SmI/4ztCFaUs6V2AiH1sfecc+57NgaryfAA2VR3v6O+CSjC1jZJKOA== - jsesc@^2.5.1: version "2.5.2" resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" @@ -5267,6 +4602,11 @@ json5@^2.1.2, json5@^2.2.3: resolved "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== +jsonc-parser@^3.2.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.1.tgz#031904571ccf929d7670ee8c547545081cb37f1a" + integrity sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA== + jsonfile@^2.1.0: version "2.4.0" resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" @@ -5458,14 +4798,6 @@ lead@^1.0.0: dependencies: flush-write-stream "^1.0.2" -levn@^0.3.0, levn@~0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA== - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - levn@^0.4.1: version "0.4.1" resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" @@ -5474,6 +4806,14 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" +levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + integrity sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA== + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + liftoff@^3.1.0: version "3.1.0" resolved "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz#c9ba6081f908670607ee79062d700df062c52ed3" @@ -5532,16 +4872,6 @@ lodash-es@^4.17.21: resolved "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== -lodash.assignin@^4.0.9: - version "4.2.0" - resolved "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2" - integrity sha512-yX/rx6d/UTVh7sSVWVSIMjfnz95evAgDFdb1ZozC35I9mSFCkmzptOzevxjgbQUsc78NR44LVHWjsoMQXy9FDg== - -lodash.bind@^4.1.4: - version "4.2.1" - resolved "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz#7ae3017e939622ac31b7d7d7dcb1b34db1690d35" - integrity sha512-lxdsn7xxlCymgLYo1gGvVrfHmkjDiyqVv62FAeF2i5ta72BipE1SLxw8hPEPLhD4/247Ijw07UQH7Hq/chT5LA== - lodash.clone@^4.3.2: version "4.5.0" resolved "https://registry.npmjs.org/lodash.clone/-/lodash.clone-4.5.0.tgz#195870450f5a13192478df4bc3d23d2dea1907b6" @@ -5552,26 +4882,6 @@ lodash.clonedeep@^4.5.0: resolved "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ== -lodash.defaults@^4.0.1: - version "4.2.0" - resolved "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c" - integrity sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ== - -lodash.filter@^4.4.0: - version "4.6.0" - resolved "https://registry.npmjs.org/lodash.filter/-/lodash.filter-4.6.0.tgz#668b1d4981603ae1cc5a6fa760143e480b4c4ace" - integrity sha512-pXYUy7PR8BCLwX5mgJ/aNtyOvuJTdZAo9EQFUvMIYugqmJxnrYaANvTbgndOzHSCSR0wnlBBfRXJL5SbWxo3FQ== - -lodash.flatten@^4.2.0: - version "4.4.0" - resolved "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" - integrity sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g== - -lodash.foreach@^4.3.0: - version "4.5.0" - resolved "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53" - integrity sha512-aEXTF4d+m05rVOAUG3z4vZZ4xVexLKZGF0lIxuHZ1Hplpk/3B6Z1+/ICICYRLm7c41Z2xiejbkCkJoTlypoXhQ== - lodash.get@^4.4.2: version "4.4.2" resolved "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" @@ -5582,32 +4892,12 @@ lodash.isequal@^4.5.0: resolved "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ== -lodash.map@^4.4.0: - version "4.6.0" - resolved "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3" - integrity sha512-worNHGKLDetmcEYDvh2stPCrrQRkP20E4l0iIS7F8EvzMqBBi7ltvFN5m1HvTf1P7Jk1txKhvFcmYsCr8O2F1Q== - -lodash.merge@^4.4.0, lodash.merge@^4.6.2: +lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -lodash.pick@^4.2.1: - version "4.4.0" - resolved "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" - integrity sha512-hXt6Ul/5yWjfklSGvLQl8vM//l3FtyHZeuelpzK6mm99pNvN9yTDruNZPEJZD1oWrqo+izBmB7oUfWgcCX7s4Q== - -lodash.reduce@^4.4.0: - version "4.6.0" - resolved "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz#f1ab6b839299ad48f784abbf476596f03b914d3b" - integrity sha512-6raRe2vxCYBhpBu+B+TtNGUzah+hQjVdu3E17wfusjyrXBka2nBS8OH/gjVZ5PvHOhWmIZTYri09Z6n/QfnNMw== - -lodash.reject@^4.4.0: - version "4.6.0" - resolved "https://registry.npmjs.org/lodash.reject/-/lodash.reject-4.6.0.tgz#80d6492dc1470864bbf583533b651f42a9f52415" - integrity sha512-qkTuvgEzYdyhiJBx42YPzPo71R1aEr0z79kAv7Ixg8wPFEjgRgJdUsGMG3Hf3OYSF/kHI79XhNlt+5Ar6OzwxQ== - -lodash.some@^4.2.2, lodash.some@^4.4.0: +lodash.some@^4.2.2: version "4.6.0" resolved "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d" integrity sha512-j7MJE+TuT51q9ggt4fSgVqro163BEFjAt3u97IqU+JA2DkWl80nFTrowzLpZ/BnpN7rrl0JA/593NAdd8p/scQ== @@ -5617,7 +4907,7 @@ lodash.sortby@^4.7.0: resolved "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" integrity sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA== -lodash@^4.0.1, lodash@^4.1.0, lodash@^4.15.0, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.17.4, lodash@^4.2.0: +lodash@^4.0.1, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21: version "4.17.21" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -5648,13 +4938,6 @@ log4js@^6.4.1: rfdc "^1.3.0" streamroller "^3.1.5" -loose-envify@^1.0.0: - version "1.4.0" - resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - loupe@^2.3.6: version "2.3.7" resolved "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz#6e69b7d4db7d3ab436328013d37d1c8c3540c697" @@ -5689,6 +4972,11 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +lunr@^2.3.9: + version "2.3.9" + resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.9.tgz#18b123142832337dd6e964df1a5a7707b25d35e1" + integrity sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow== + make-error@^1.1.1: version "1.3.6" resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" @@ -5713,10 +5001,10 @@ map-visit@^1.0.0: dependencies: object-visit "^1.0.0" -marked@0.3.19: - version "0.3.19" - resolved "https://registry.npmjs.org/marked/-/marked-0.3.19.tgz#5d47f709c4c9fc3c216b6d46127280f40b39d790" - integrity sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg== +marked@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/marked/-/marked-4.3.0.tgz#796362821b019f734054582038b116481b456cf3" + integrity sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A== matchdep@^2.0.0: version "2.0.0" @@ -5819,11 +5107,6 @@ mime@^2.5.2: resolved "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367" integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg== -mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - min-document@^2.19.0: version "2.19.0" resolved "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" @@ -5866,12 +5149,7 @@ minimatch@^9.0.1, minimatch@^9.0.3, minimatch@^9.0.4: dependencies: brace-expansion "^2.0.1" -minimist@1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" - integrity sha512-7Wl+Jz+IGWuSdgsQEJ4JunV0si/iMhg42MnQQG6h1R6TNeVenp4U9x5CC5v/gYqz/fENLQITAWXidNtVL0NNbw== - -minimist@^1.1.0, minimist@^1.2.3, minimist@^1.2.6: +minimist@^1.2.3, minimist@^1.2.6: version "1.2.8" resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== @@ -5889,7 +5167,7 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp@^0.5.1, mkdirp@^0.5.4, mkdirp@^0.5.5: +mkdirp@^0.5.4, mkdirp@^0.5.5: version "0.5.6" resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== @@ -5978,11 +5256,6 @@ mute-stdout@^1.0.0: resolved "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz#acb0300eb4de23a7ddeec014e3e96044b3472331" integrity sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg== -mute-stream@0.0.8: - version "0.0.8" - resolved "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" - integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== - nan@^2.12.1: version "2.19.0" resolved "https://registry.npmjs.org/nan/-/nan-2.19.0.tgz#bb58122ad55a6c5bc973303908d5b16cfdd5a8c0" @@ -6030,11 +5303,6 @@ next-tick@^1.1.0: resolved "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz#1836ee30ad56d67ef281b22bd199f709449b35eb" integrity sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ== -nice-try@^1.0.4: - version "1.0.5" - resolved "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" - integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== - nise@^5.1.5: version "5.1.9" resolved "https://registry.npmjs.org/nise/-/nise-5.1.9.tgz#0cb73b5e4499d738231a473cd89bd8afbb618139" @@ -6094,23 +5362,11 @@ now-and-later@^2.0.0: dependencies: once "^1.3.2" -nth-check@~1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c" - integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg== - dependencies: - boolbase "~1.0.0" - number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" integrity sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ== -"nwmatcher@>= 1.3.7 < 2.0.0": - version "1.4.4" - resolved "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.4.4.tgz#2285631f34a95f0d0395cd900c96ed39b58f346e" - integrity sha512-3iuY4N5dhgMpCUrOVnuAdGrgxVqV2cJpM+XNccjR2DKOB1RUP0aA+wGXEiNziG/UKboFyGBIoKOaNlJxx8bciQ== - nwsapi@^2.0.9, nwsapi@^2.2.4: version "2.2.7" resolved "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz#738e0707d3128cb750dddcfe90e4610482df0f30" @@ -6224,19 +5480,12 @@ once@^1.3.0, once@^1.3.1, once@^1.3.2, once@^1.4.0: dependencies: wrappy "1" -onetime@^5.1.0: - version "5.1.2" - resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== - dependencies: - mimic-fn "^2.1.0" - opener@^1.5.2: version "1.5.2" resolved "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A== -optionator@^0.8.1, optionator@^0.8.3: +optionator@^0.8.1: version "0.8.3" resolved "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== @@ -6279,11 +5528,6 @@ os-shim@^0.1.2: resolved "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917" integrity sha512-jd0cvB8qQ5uVt0lvCIexBaROw1KyKm5sbulg2fWOHjETisuCzWyt+eTZKEMs8v6HwzoGs8xik26jg7eCM6pS+A== -os-tmpdir@~1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" - integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== - p-limit@^2.2.0: version "2.3.0" resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" @@ -6370,18 +5614,6 @@ parse5@5.1.0: resolved "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz#c59341c9723f414c452975564c7c00a68d58acd2" integrity sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ== -parse5@^1.5.1: - version "1.5.1" - resolved "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94" - integrity sha512-w2jx/0tJzvgKwZa58sj2vAYq/S/K1QJfIB3cWYea/Iu1scFPDQQ3IQiVZTHWtRBwAjv2Yd7S/xeZf3XqLDb3bA== - -parse5@^3.0.1: - version "3.0.3" - resolved "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz#042f792ffdd36851551cf4e9e066b3874ab45b5c" - integrity sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA== - dependencies: - "@types/node" "*" - parse5@^7.1.2: version "7.1.2" resolved "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz#0736bebbfd77793823240a23b7fc5e010b7f8e32" @@ -6421,11 +5653,6 @@ path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== -path-key@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" - integrity sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw== - path-key@^3.1.0: version "3.1.1" resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" @@ -6732,11 +5959,6 @@ progress@^1.1.8: resolved "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" integrity sha512-UdA8mJ4weIkUBO224tIarHzuHs4HuYiJvsuGT7j/SPQiUJVjYvNDBIPa0hAorduOfjGohB/qHWRa/lrrWX/mXw== -progress@^2.0.0: - version "2.0.3" - resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" - integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== - proto-list@~1.2.1: version "1.2.4" resolved "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" @@ -6891,17 +6113,7 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" -readable-stream@1.1: - version "1.1.13" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.13.tgz#f6eef764f514c89e2b9e23146a75ba106756d23e" - integrity sha512-E98tWzqShvKDGpR2MbjsDkDQWLW2TfWUC15H4tNQhIJ5Lsta84l8nUGL9/ybltGwe+wZzWPpc1Kmd2wQP4bdCA== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -"readable-stream@2 || 3", readable-stream@3, readable-stream@^3.0.6, readable-stream@^3.1.1: +"readable-stream@2 || 3", readable-stream@3, readable-stream@^3.0.6: version "3.6.2" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== @@ -6960,11 +6172,6 @@ redux@^4.2.0: dependencies: "@babel/runtime" "^7.9.2" -regenerator-runtime@^0.11.0: - version "0.11.1" - resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" - integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== - regenerator-runtime@^0.14.0: version "0.14.1" resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" @@ -6995,11 +6202,6 @@ regexp.prototype.flags@^1.5.2: es-errors "^1.3.0" set-function-name "^2.0.1" -regexpp@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f" - integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw== - remove-bom-buffer@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz#c2bf1e377520d324f623892e33c10cac2c252b53" @@ -7032,20 +6234,6 @@ repeat-string@^1.5.2, repeat-string@^1.6.1: resolved "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w== -repeating@^1.1.0: - version "1.1.3" - resolved "https://registry.npmjs.org/repeating/-/repeating-1.1.3.tgz#3d4114218877537494f97f77f9785fab810fa4ac" - integrity sha512-Nh30JLeMHdoI+AsQ5eblhZ7YlTsM9wiJQe/AHIunlK3KWzvXhXb36IJ7K1IOeRjIOtzMjdUHjwXUFxKJoPTSOg== - dependencies: - is-finite "^1.0.0" - -repeating@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" - integrity sha512-ZqtSMuVybkISo2OWvqvm7iHSWngvdaW3IpsT9/uP8v4gMi591LY6h35wdOfvQdWCKFWZWm2Y1Opp4kV7vQKT6A== - dependencies: - is-finite "^1.0.0" - replace-ext@0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz#29bbd92078a739f0bcce2b4ee41e837953522924" @@ -7102,7 +6290,7 @@ request-promise-native@^1.0.5: stealthy-require "^1.1.1" tough-cookie "^2.3.3" -request@^2.55.0, request@^2.81.0, request@^2.88.0: +request@^2.81.0, request@^2.88.0: version "2.88.2" resolved "https://registry.npmjs.org/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== @@ -7189,14 +6377,6 @@ resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.20.0, resolve@^1.4.0 path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" -restore-cursor@^3.1.0: - version "3.1.0" - resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" - integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== - dependencies: - onetime "^5.1.0" - signal-exit "^3.0.2" - ret@~0.1.10: version "0.1.15" resolved "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" @@ -7212,13 +6392,6 @@ rfdc@^1.3.0: resolved "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz#2b6d4df52dffe8bb346992a10ea9451f24373a8f" integrity sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg== -rimraf@2.6.3: - version "2.6.3" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" - integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA== - dependencies: - glob "^7.1.3" - rimraf@^2.6.2: version "2.7.1" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" @@ -7238,11 +6411,6 @@ rrweb-cssom@^0.6.0: resolved "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz#ed298055b97cbddcdeb278f904857629dec5e0e1" integrity sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw== -run-async@^2.4.0: - version "2.4.1" - resolved "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" - integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== - run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -7250,13 +6418,6 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -rxjs@^6.6.0: - version "6.6.7" - resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" - integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== - dependencies: - tslib "^1.9.0" - safe-array-concat@^1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz#81d77ee0c4e8b863635227c721278dd524c20edb" @@ -7307,11 +6468,6 @@ sass@^1.74.1: immutable "^4.0.0" source-map-js ">=0.6.2 <2.0.0" -sax@^1.1.4: - version "1.3.0" - resolved "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz#a5dbe77db3be05c9d1ee7785dbd3ea9de51593d0" - integrity sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA== - saxes@^3.1.5: version "3.1.11" resolved "https://registry.npmjs.org/saxes/-/saxes-3.1.11.tgz#d59d1fd332ec92ad98a2e0b2ee644702384b1c5b" @@ -7342,12 +6498,12 @@ semver-greatest-satisfied-range@^1.1.0: dependencies: sver-compat "^1.5.0" -"semver@2 || 3 || 4 || 5", semver@^5.5.0: +"semver@2 || 3 || 4 || 5": version "5.7.2" resolved "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== -semver@^6.1.2, semver@^6.3.1: +semver@^6.3.1: version "6.3.1" resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== @@ -7446,6 +6602,16 @@ shebang-regex@^3.0.0: resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== +shiki@^0.14.7: + version "0.14.7" + resolved "https://registry.yarnpkg.com/shiki/-/shiki-0.14.7.tgz#c3c9e1853e9737845f1d2ef81b31bcfb07056d4e" + integrity sha512-dNPAPrxSc87ua2sKJ3H5dQ/6ZaY8RNnaAqK+t0eG7p0Soi2ydiqbGOTaZCqaYvA/uZYfS1LJnemt3Q+mSfcPCg== + dependencies: + ansi-sequence-parser "^1.1.0" + jsonc-parser "^3.2.0" + vscode-oniguruma "^1.7.0" + vscode-textmate "^8.0.0" + shortcut-buttons-flatpickr@^0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/shortcut-buttons-flatpickr/-/shortcut-buttons-flatpickr-0.4.0.tgz#a36e0a88a670ed2637b7b1adb5bee0914c29a7e7" @@ -7461,11 +6627,6 @@ side-channel@^1.0.4: get-intrinsic "^1.2.4" object-inspect "^1.13.1" -signal-exit@^3.0.2: - version "3.0.7" - resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" - integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== - signal-exit@^4.0.1: version "4.1.0" resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" @@ -7507,15 +6668,6 @@ slash@^3.0.0: resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== -slice-ansi@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" - integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ== - dependencies: - ansi-styles "^3.2.0" - astral-regex "^1.0.0" - is-fullwidth-code-point "^2.0.0" - snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" @@ -7604,7 +6756,7 @@ source-map-url@^0.4.0: resolved "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz#0af66605a745a5a2f91cf1bbf8a7afbc283dec56" integrity sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw== -source-map@^0.5.0, source-map@^0.5.1, source-map@^0.5.6, source-map@^0.5.7: +source-map@^0.5.1, source-map@^0.5.6: version "0.5.7" resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== @@ -7658,6 +6810,14 @@ spdx-expression-parse@^3.0.0: spdx-exceptions "^2.1.0" spdx-license-ids "^3.0.0" +spdx-expression-parse@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz#a23af9f3132115465dac215c099303e4ceac5794" + integrity sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + spdx-license-ids@^3.0.0: version "3.0.17" resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz#887da8aa73218e51a1d917502d79863161a93f9c" @@ -7670,11 +6830,6 @@ split-string@^3.0.1, split-string@^3.0.2: dependencies: extend-shallow "^3.0.0" -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== - sshpk@^1.7.0: version "1.18.0" resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz#1663e55cddf4d688b86a46b77f0d5fe363aba028" @@ -7775,15 +6930,6 @@ string-width@^1.0.1, string-width@^1.0.2: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -string-width@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" - integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== - dependencies: - emoji-regex "^7.0.1" - is-fullwidth-code-point "^2.0.0" - strip-ansi "^5.1.0" - string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" resolved "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" @@ -7828,11 +6974,6 @@ string_decoder@^1.1.1: dependencies: safe-buffer "~5.2.0" -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" - integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ== - string_decoder@~1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" @@ -7870,13 +7011,6 @@ strip-ansi@^4.0.0: dependencies: ansi-regex "^3.0.0" -strip-ansi@^5.1.0, strip-ansi@^5.2.0: - version "5.2.0" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" - integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== - dependencies: - ansi-regex "^4.1.0" - strip-ansi@^7.0.1: version "7.1.0" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz#d5b6568ca689d8561370b0707685d22434faff45" @@ -7899,7 +7033,7 @@ strip-bom@^2.0.0: dependencies: is-utf8 "^0.2.0" -strip-json-comments@3.1.1, strip-json-comments@^3.0.1, strip-json-comments@^3.1.1: +strip-json-comments@3.1.1, strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== @@ -7911,11 +7045,6 @@ supports-color@8.1.1, supports-color@^8.0.0, supports-color@^8.1.1: dependencies: has-flag "^4.0.0" -supports-color@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" - integrity sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g== - supports-color@^5.3.0: version "5.5.0" resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" @@ -7943,31 +7072,11 @@ sver-compat@^1.5.0: es6-iterator "^2.0.1" es6-symbol "^3.1.1" -"symbol-tree@>= 3.1.0 < 4.0.0", symbol-tree@^3.2.2, symbol-tree@^3.2.4: +symbol-tree@^3.2.2, symbol-tree@^3.2.4: version "3.2.4" resolved "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== -table@^5.2.3: - version "5.4.6" - resolved "https://registry.npmjs.org/table/-/table-5.4.6.tgz#1292d19500ce3f86053b05f0e8e7e4a3bb21079e" - integrity sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug== - dependencies: - ajv "^6.10.2" - lodash "^4.17.14" - slice-ansi "^2.1.0" - string-width "^3.0.0" - -taffydb@2.7.2: - version "2.7.2" - resolved "https://registry.npmjs.org/taffydb/-/taffydb-2.7.2.tgz#7bf8106a5c1a48251b3e3bc0a0e1732489fd0dc8" - integrity sha512-R6es6/C/m1xXZckrSam4j07YKbd74437mRJ/R944S1hLG7mIl2/EQW7tQPI4XiX7jTduFzz31g7466a2BcsglQ== - -taffydb@2.7.3: - version "2.7.3" - resolved "https://registry.npmjs.org/taffydb/-/taffydb-2.7.3.tgz#2ad37169629498fca5bc84243096d3cde0ec3a34" - integrity sha512-GQ3gtYFSOAxSMN/apGtDKKkbJf+8izz5YfbGqIsUc7AMiQOapARZ76dhilRY2h39cynYxBFdafQo5HUL5vgkrg== - tapable@^2.1.1, tapable@^2.2.0: version "2.2.1" resolved "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" @@ -8038,7 +7147,7 @@ through2@^4.0.2: dependencies: readable-stream "3" -through@^2.3.6, through@^2.3.8: +through@^2.3.8: version "2.3.8" resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== @@ -8060,13 +7169,6 @@ tippy.js@^6.3.7: dependencies: "@popperjs/core" "^2.9.0" -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - tmp@^0.2.1: version "0.2.3" resolved "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz#eb783cc22bc1e8bebd0671476d46ea4eb32a79ae" @@ -8080,11 +7182,6 @@ to-absolute-glob@^2.0.0, to-absolute-glob@^2.0.2: is-absolute "^1.0.0" is-negated-glob "^1.0.0" -to-fast-properties@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" - integrity sha512-lxrWP8ejsq+7E3nNjwYmUBMAgjMTZoTI+sdBOpvNyijeDLa29LUn9QaoXAHv4+Z578hbmHHJKZknzxVtvo77og== - to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" @@ -8139,7 +7236,7 @@ totalist@^3.0.0: resolved "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz#ba3a3d600c915b1a97872348f79c127475f6acf8" integrity sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ== -tough-cookie@^2.2.0, tough-cookie@^2.3.3, tough-cookie@^2.5.0, tough-cookie@~2.5.0: +tough-cookie@^2.3.3, tough-cookie@^2.5.0, tough-cookie@~2.5.0: version "2.5.0" resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== @@ -8171,7 +7268,7 @@ tr46@^4.1.1: dependencies: punycode "^2.3.0" -tr46@~0.0.1, tr46@~0.0.3: +tr46@~0.0.3: version "0.0.3" resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== @@ -8185,11 +7282,6 @@ traverse@^0.6.6: typedarray.prototype.slice "^1.0.3" which-typed-array "^1.1.15" -trim-right@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" - integrity sha512-WZGXGstmCWgeevgTL54hrCuw1dyMQIzWy7ZfqRJfSmJZBwklI15egmQytFP6bPidmw3M8d5yEowl1niq4vmqZw== - ts-api-utils@^1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" @@ -8230,11 +7322,6 @@ tsc@^2.0.4: resolved "https://registry.yarnpkg.com/tsc/-/tsc-2.0.4.tgz#5f6499146abea5dca4420b451fa4f2f9345238f5" integrity sha512-fzoSieZI5KKJVBYGvwbVZs/J5za84f2lSTLPYf6AGiIf43tZ3GNrI1QzTLcjtyDDP4aLxd46RTZq1nQxe7+k5Q== -tslib@^1.9.0: - version "1.14.1" - resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== - tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" @@ -8271,16 +7358,6 @@ type-fest@^0.20.2: resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== -type-fest@^0.21.3: - version "0.21.3" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" - integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== - -type-fest@^0.8.1: - version "0.8.1" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" - integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== - type-func@^1.0.1: version "1.0.3" resolved "https://registry.npmjs.org/type-func/-/type-func-1.0.3.tgz#ab184234ae80d8d50057cefeff3b2d97d08ae9b0" @@ -8365,6 +7442,16 @@ typedarray@^0.0.6: resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA== +typedoc@^0.25.13: + version "0.25.13" + resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.25.13.tgz#9a98819e3b2d155a6d78589b46fa4c03768f0922" + integrity sha512-pQqiwiJ+Z4pigfOnnysObszLiU3mVLWAExSPf+Mu06G/qsc3wzbuM56SZQvONhHLncLUhYzOVkjFFpFfL5AzhQ== + dependencies: + lunr "^2.3.9" + marked "^4.3.0" + minimatch "^9.0.3" + shiki "^0.14.7" + typescript@5.3.2: version "5.3.2" resolved "https://registry.npmjs.org/typescript/-/typescript-5.3.2.tgz#00d1c7c1c46928c5845c1ee8d0cc2791031d4c43" @@ -8529,11 +7616,6 @@ v8-compile-cache-lib@^3.0.1: resolved "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== -v8-compile-cache@^2.0.3: - version "2.4.0" - resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz#cdada8bec61e15865f05d097c5f4fd30e94dc128" - integrity sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw== - v8flags@^3.2.0: version "3.2.0" resolved "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz#b243e3b4dfd731fa774e7492128109a0fe66d656" @@ -8656,6 +7738,16 @@ void-elements@^2.0.0: resolved "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec" integrity sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung== +vscode-oniguruma@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz#439bfad8fe71abd7798338d1cd3dc53a8beea94b" + integrity sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA== + +vscode-textmate@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-8.0.0.tgz#2c7a3b1163ef0441097e0b5d6389cd5504b59e5d" + integrity sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg== + w3c-hr-time@^1.0.1: version "1.0.2" resolved "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" @@ -8687,11 +7779,6 @@ watchpack@^2.4.1: glob-to-regexp "^0.4.1" graceful-fs "^4.1.2" -webidl-conversions@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-2.0.1.tgz#3bf8258f7d318c7443c36f2e169402a1a6703506" - integrity sha512-OZ7I/f0sM+T28T2/OXinNGfmvjm3KKptdyQy8NPRZyLfYBn+9vt72Bfr+uQaE9OvWyxJjQ5kHFygH2wOTUb76g== - webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" @@ -8838,13 +7925,6 @@ whatwg-mimetype@^3.0.0: resolved "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz#5fa1a7623867ff1af6ca3dc72ad6b8a4208beba7" integrity sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q== -whatwg-url-compat@~0.6.5: - version "0.6.5" - resolved "https://registry.npmjs.org/whatwg-url-compat/-/whatwg-url-compat-0.6.5.tgz#00898111af689bb097541cd5a45ca6c8798445bf" - integrity sha512-vbg5+JVNwGtHRI3GheZGWrcUlxF9BXHbA80dLa+2XqJjlV/BK6upoi2j8dIRW9FGPUUyaMm7Hf1pTexHnsk85g== - dependencies: - tr46 "~0.0.1" - whatwg-url@^12.0.0, whatwg-url@^12.0.1: version "12.0.1" resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-12.0.1.tgz#fd7bcc71192e7c3a2a97b9a8d6b094853ed8773c" @@ -8980,13 +8060,6 @@ wrappy@1: resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== -write@1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3" - integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig== - dependencies: - mkdirp "^0.5.1" - written-number@^0.11.1: version "0.11.1" resolved "https://registry.npmjs.org/written-number/-/written-number-0.11.1.tgz#ef060a7b5ad5ff8fbf4ff88daa8fb2260726ecc9" @@ -9014,11 +8087,6 @@ ws@~8.11.0: resolved "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz#6a0d36b8edfd9f96d8b25683db2f8d7de6e8e143" integrity sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg== -"xml-name-validator@>= 2.0.1 < 3.0.0": - version "2.0.1" - resolved "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635" - integrity sha512-jRKe/iQYMyVJpzPH+3HL97Lgu5HrCfii+qSo+TfjKHtOnvbnvdVfMYrn9Q34YV81M2e5sviJlI6Ko9y+nByzvA== - xml-name-validator@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a"