diff --git a/bin.js b/bin.js new file mode 100755 index 0000000000..317b4712e6 --- /dev/null +++ b/bin.js @@ -0,0 +1,2 @@ +#!/usr/bin/env node +require('./dist/src/bin'); diff --git a/package.json b/package.json index 32a342a4de..129277b19d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@payloadcms/payload", - "version": "0.1.6", + "version": "0.1.9", "description": "CMS and Application Framework", "license": "ISC", "author": "Payload CMS LLC", @@ -8,12 +8,12 @@ "typings": "./dist/src/index.d.ts", "sideEffects": false, "bin": { - "payload": "./dist/src/bin/index.js" + "payload": "./bin.js" }, "scripts": { "copyfiles": "copyfiles src/**/*.{html,css,scss,ttf,woff,woff2,eot,svg,jpg,png} dist/", "build:components": "webpack --config src/webpack/components.config.js", - "build": "cross-env PAYLOAD_CONFIG_PATH=demo/payload.config.js node src/bin/build", + "build": "cross-env PAYLOAD_CONFIG_PATH=demo/payload.config.js node dist/src/bin/build", "build:tsc": "tsc", "build:analyze": "cross-env PAYLOAD_CONFIG_PATH=demo/payload.config.js PAYLOAD_ANALYZE_BUNDLE=true node src/bin/build", "cov": "npm run core:build && node ./node_modules/jest/bin/jest.js src/tests --coverage", @@ -40,11 +40,11 @@ "@faceless-ui/modal": "^1.0.4", "@faceless-ui/scroll-info": "^1.1.1", "@faceless-ui/window-info": "^1.2.2", - "@payloadcms/config-provider": "0.0.7", + "@payloadcms/config-provider": "0.0.9", "@typescript-eslint/parser": "4.0.1", "@udecode/slate-plugins": "^0.64.3", "ajv": "^6.12.6", - "async-some": "^1.0.2", + "asap": "^2.0.6", "autoprefixer": "^9.7.4", "babel-jest": "^26.3.0", "babel-loader": "^8.1.0", @@ -52,6 +52,7 @@ "compression": "^1.7.4", "connect-history-api-fallback": "^1.6.0", "css-loader": "^5.0.1", + "css-minimizer-webpack-plugin": "^1.1.5", "date-fns": "^2.14.0", "deepmerge": "^4.2.2", "dotenv": "^6.0.0", @@ -61,6 +62,7 @@ "express-rate-limit": "^5.1.3", "falsey": "^1.0.0", "file-loader": "^1.1.11", + "find-up": "^5.0.0", "flatley": "^5.2.0", "graphql": "15.4.0", "graphql-playground-middleware-express": "^1.7.14", @@ -86,7 +88,6 @@ "node-sass": "^4.14.1", "nodemailer": "^6.4.2", "object-to-formdata": "^3.0.9", - "optimize-css-assets-webpack-plugin": "^5.0.4", "passport": "^0.4.1", "passport-anonymous": "^1.0.1", "passport-headerapikey": "^1.2.1", @@ -134,12 +135,14 @@ "webpack-bundle-analyzer": "^3.8.0", "webpack-cli": "^4.2.0", "webpack-dev-middleware": "^4.0.2", - "webpack-hot-middleware": "^2.25.0" + "webpack-hot-middleware": "^2.25.0", + "wrappy": "^1.0.2" }, "devDependencies": { "@testing-library/jest-dom": "^5.11.4", "@testing-library/react": "^11.0.4", "@trbl/eslint-config": "^1.2.4", + "@types/asap": "^2.0.0", "@types/autoprefixer": "^9.7.2", "@types/babel__core": "^7.1.12", "@types/babel__plugin-transform-runtime": "^7.9.1", @@ -154,6 +157,7 @@ "@types/express-rate-limit": "^5.1.0", "@types/extract-text-webpack-plugin": "^3.0.4", "@types/file-loader": "^4.2.0", + "@types/find-up": "^4.0.0", "@types/html-webpack-plugin": "^3.2.4", "@types/ignore-styles": "^5.0.0", "@types/is-hotkey": "^0.1.2", @@ -167,6 +171,7 @@ "@types/mongodb": "^3.5.34", "@types/mongoose": "^5.10.1", "@types/mongoose-paginate-v2": "^1.3.8", + "@types/node-fetch": "^2.5.7", "@types/node-sass": "^4.11.1", "@types/nodemailer": "^6.4.0", "@types/nodemon": "^1.19.0", @@ -220,6 +225,7 @@ "typescript": "^4.1.2" }, "files": [ + "bin.js", "dist", "docs", "components", diff --git a/src/admin/components/elements/ReactSelect/index.tsx b/src/admin/components/elements/ReactSelect/index.tsx index b7e992d05f..51e6f282f9 100644 --- a/src/admin/components/elements/ReactSelect/index.tsx +++ b/src/admin/components/elements/ReactSelect/index.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import Select from 'react-select'; import { Props } from './types'; import Chevron from '../../icons/Chevron'; diff --git a/src/admin/components/forms/Form/index.tsx b/src/admin/components/forms/Form/index.tsx index be1e74a48f..9d86291c4d 100644 --- a/src/admin/components/forms/Form/index.tsx +++ b/src/admin/components/forms/Form/index.tsx @@ -5,10 +5,10 @@ import { objectToFormData } from 'object-to-formdata'; import { useHistory } from 'react-router-dom'; import PropTypes from 'prop-types'; import { toast } from 'react-toastify'; +import { useAuth } from '@payloadcms/config-provider'; import { useLocale } from '../../utilities/Locale'; import { requests } from '../../../api'; import useThrottledEffect from '../../../hooks/useThrottledEffect'; -import { useAuth } from '@payloadcms/config-provider'; import fieldReducer from './fieldReducer'; import initContextState from './initContextState'; import reduceFieldsToValues from './reduceFieldsToValues'; @@ -24,7 +24,7 @@ import './index.scss'; const baseClass = 'form'; -const Form = (props) => { +const Form: React.FC = (props) => { const { disabled, onSubmit, diff --git a/src/admin/components/forms/RenderFields/index.tsx b/src/admin/components/forms/RenderFields/index.tsx index ca0c2ba01f..9b3f0fc67f 100644 --- a/src/admin/components/forms/RenderFields/index.tsx +++ b/src/admin/components/forms/RenderFields/index.tsx @@ -1,7 +1,7 @@ import React, { createContext, useEffect, useContext, useState } from 'react'; -import PropTypes from 'prop-types'; import RenderCustomComponent from '../../utilities/RenderCustomComponent'; import useIntersect from '../../../hooks/useIntersect'; +import { Props, Context } from './types'; const baseClass = 'render-fields'; @@ -9,11 +9,11 @@ const intersectionObserverOptions = { rootMargin: '1000px', }; -const RenderedFieldContext = createContext({}); +const RenderedFieldContext = createContext({} as Context); -export const useRenderedFields = () => useContext(RenderedFieldContext); +export const useRenderedFields = (): Context => useContext(RenderedFieldContext); -const RenderFields = (props) => { +const RenderFields: React.FC = (props) => { const { fieldSchema, fieldTypes, @@ -135,26 +135,4 @@ const RenderFields = (props) => { return null; }; -RenderFields.defaultProps = { - filter: null, - readOnly: false, - permissions: {}, - operation: undefined, - className: undefined, -}; - -RenderFields.propTypes = { - fieldSchema: PropTypes.arrayOf( - PropTypes.shape({}), - ).isRequired, - fieldTypes: PropTypes.shape({ - hidden: PropTypes.function, - }).isRequired, - filter: PropTypes.func, - permissions: PropTypes.shape({}), - readOnly: PropTypes.bool, - operation: PropTypes.string, - className: PropTypes.string, -}; - export default RenderFields; diff --git a/src/admin/components/forms/RenderFields/types.ts b/src/admin/components/forms/RenderFields/types.ts new file mode 100644 index 0000000000..524b544336 --- /dev/null +++ b/src/admin/components/forms/RenderFields/types.ts @@ -0,0 +1,17 @@ +import { CollectionPermission, GlobalPermission } from '../../../../auth/types'; +import { Field } from '../../../../fields/config/types'; + +export type Operation = 'create' | 'update' + +export type Context = { + operation: Operation +} + +export type Props = { + className?: string + operation: Operation + readOnly: boolean + permissions: CollectionPermission | GlobalPermission + filter: (field: Field) => boolean + fieldSchema: Field[] +} diff --git a/src/admin/components/forms/field-types/Relationship/index.tsx b/src/admin/components/forms/field-types/Relationship/index.tsx index 8751f415f5..a64223764e 100644 --- a/src/admin/components/forms/field-types/Relationship/index.tsx +++ b/src/admin/components/forms/field-types/Relationship/index.tsx @@ -2,14 +2,16 @@ import React, { Component, useCallback, } from 'react'; import PropTypes from 'prop-types'; -import some from 'async-some'; import { useConfig } from '@payloadcms/config-provider'; +import some from '../../../../../utilities/asyncSome'; import withCondition from '../../withCondition'; import ReactSelect from '../../../elements/ReactSelect'; import useFieldType from '../../useFieldType'; import Label from '../../Label'; import Error from '../../Error'; import { relationship } from '../../../../../fields/validations'; +import { PaginatedDocs } from '../../../../../collections/config/types'; +import { RelationshipProps, OptionsPage } from './types'; import './index.scss'; @@ -17,7 +19,7 @@ const maxResultsPerRequest = 10; const baseClass = 'relationship'; -class Relationship extends Component { +class Relationship extends Component { constructor(props) { super(props); @@ -77,7 +79,7 @@ class Relationship extends Component { const fieldToSearch = collection?.admin?.useAsTitle || 'id'; const searchParam = search ? `&where[${fieldToSearch}][like]=${search}` : ''; const response = await fetch(`${serverURL}${api}/${relation}?limit=${maxResultsPerRequest}&page=${lastLoadedPage}${searchParam}`); - const data = await response.json(); + const data: PaginatedDocs = await response.json(); if (response.ok) { if (data.hasNextPage) { @@ -87,7 +89,7 @@ class Relationship extends Component { }); } - return callback({ relation, data }); + return callback(true, { relation, data }); } let error = 'There was a problem loading options for this field.'; @@ -99,7 +101,7 @@ class Relationship extends Component { return this.setState({ errorLoading: error, }); - }, (lastPage, nextPage) => { + }, (lastPage: OptionsPage, nextPage: OptionsPage) => { if (nextPage) { const { data, relation } = nextPage; this.addOptions(data, relation); diff --git a/src/admin/components/forms/field-types/Relationship/types.ts b/src/admin/components/forms/field-types/Relationship/types.ts new file mode 100644 index 0000000000..3302039a3b --- /dev/null +++ b/src/admin/components/forms/field-types/Relationship/types.ts @@ -0,0 +1,25 @@ +import React from 'react'; +import { PaginatedDocs } from '../../../../../collections/config/types'; +import { Config } from '../../../../../config/types'; + +export type OptionsPage = { + relation: string + data: PaginatedDocs +} + +export type RelationshipProps = { + required: boolean + errorMessage: string + hasMany: boolean + showError: boolean + value: unknown + path: string + formProcessing: boolean + admin: { + readOnly: boolean + style: React.CSSProperties + width: string + } + relationTo: string | string[] + config: Config +} diff --git a/src/admin/components/modals/LeaveWithoutSaving/index.tsx b/src/admin/components/modals/LeaveWithoutSaving/index.tsx index a13368477b..ca1234c7c3 100644 --- a/src/admin/components/modals/LeaveWithoutSaving/index.tsx +++ b/src/admin/components/modals/LeaveWithoutSaving/index.tsx @@ -1,20 +1,20 @@ import React from 'react'; import NavigationPrompt from 'react-router-navigation-prompt'; +import { useAuth } from '@payloadcms/config-provider'; import { useFormModified } from '../../forms/Form/context'; import MinimalTemplate from '../../templates/Minimal'; import Button from '../../elements/Button'; -import { useAuth } from '@payloadcms/config-provider'; import './index.scss'; const modalSlug = 'leave-without-saving'; -const LeaveWithoutSaving = () => { +const LeaveWithoutSaving: React.FC = () => { const modified = useFormModified(); const { user } = useAuth(); return ( - + {({ onConfirm, onCancel }) => (
diff --git a/src/admin/components/modals/StayLoggedIn/index.tsx b/src/admin/components/modals/StayLoggedIn/index.tsx index 137e12c323..9f3f4d501e 100644 --- a/src/admin/components/modals/StayLoggedIn/index.tsx +++ b/src/admin/components/modals/StayLoggedIn/index.tsx @@ -5,12 +5,13 @@ import { useModal, Modal } from '@faceless-ui/modal'; import { useConfig } from '@payloadcms/config-provider'; import MinimalTemplate from '../../templates/Minimal'; import Button from '../../elements/Button'; +import { Props } from './types'; import './index.scss'; const baseClass = 'stay-logged-in'; -const StayLoggedInModal = (props) => { +const StayLoggedInModal: React.FC = (props) => { const { refreshCookie } = props; const history = useHistory(); const { routes: { admin } } = useConfig(); diff --git a/src/admin/components/modals/StayLoggedIn/types.ts b/src/admin/components/modals/StayLoggedIn/types.ts new file mode 100644 index 0000000000..578f5616f6 --- /dev/null +++ b/src/admin/components/modals/StayLoggedIn/types.ts @@ -0,0 +1,4 @@ + +export type Props = { + refreshCookie: () => void +} diff --git a/src/admin/components/templates/Default/index.tsx b/src/admin/components/templates/Default/index.tsx index 781376ba21..3301de2777 100644 --- a/src/admin/components/templates/Default/index.tsx +++ b/src/admin/components/templates/Default/index.tsx @@ -1,16 +1,16 @@ import React from 'react'; -import PropTypes from 'prop-types'; -import DefaultNav from '../../elements/Nav'; import { useConfig } from '@payloadcms/config-provider'; +import DefaultNav from '../../elements/Nav'; import { StepNavProvider } from '../../elements/StepNav'; import RenderCustomComponent from '../../utilities/RenderCustomComponent'; import Meta from '../../utilities/Meta'; +import { Props } from './types'; import './index.scss'; const baseClass = 'template-default'; -const Default = ({ children, className }) => { +const Default: React.FC = ({ children, className }) => { const { admin: { components: { @@ -44,16 +44,4 @@ const Default = ({ children, className }) => { ); }; -Default.defaultProps = { - className: '', -}; - -Default.propTypes = { - children: PropTypes.oneOfType([ - PropTypes.arrayOf(PropTypes.node), - PropTypes.node, - ]).isRequired, - className: PropTypes.string, -}; - export default Default; diff --git a/src/admin/components/templates/Default/types.ts b/src/admin/components/templates/Default/types.ts new file mode 100644 index 0000000000..8f2da3ac4b --- /dev/null +++ b/src/admin/components/templates/Default/types.ts @@ -0,0 +1,3 @@ +export type Props = { + className?: string, +}; diff --git a/src/admin/components/templates/Minimal/index.tsx b/src/admin/components/templates/Minimal/index.tsx index 273c138436..8b6039d14b 100644 --- a/src/admin/components/templates/Minimal/index.tsx +++ b/src/admin/components/templates/Minimal/index.tsx @@ -1,13 +1,16 @@ import React from 'react'; -import PropTypes from 'prop-types'; +import { Props } from './types'; import './index.scss'; const baseClass = 'template-minimal'; -const Minimal = (props) => { +const Minimal: React.FC = (props) => { const { - className, style, children, width, + className, + style = {}, + children, + width = 'normal', } = props; const classes = [ @@ -28,17 +31,4 @@ const Minimal = (props) => { ); }; -Minimal.defaultProps = { - className: null, - style: {}, - width: 'normal', -}; - -Minimal.propTypes = { - className: PropTypes.string, - style: PropTypes.shape({}), - children: PropTypes.node.isRequired, - width: PropTypes.oneOf(['normal', 'wide']), -}; - export default Minimal; diff --git a/src/admin/components/templates/Minimal/types.ts b/src/admin/components/templates/Minimal/types.ts new file mode 100644 index 0000000000..43b37a1af5 --- /dev/null +++ b/src/admin/components/templates/Minimal/types.ts @@ -0,0 +1,7 @@ +import React from 'react'; + +export type Props = { + className?: string, + width?: 'normal' | 'wide' + style?: React.CSSProperties +}; diff --git a/src/admin/components/utilities/Locale/index.tsx b/src/admin/components/utilities/Locale/index.tsx index 9b61e96eef..f73d86232b 100644 --- a/src/admin/components/utilities/Locale/index.tsx +++ b/src/admin/components/utilities/Locale/index.tsx @@ -5,17 +5,17 @@ import PropTypes from 'prop-types'; import { useConfig } from '@payloadcms/config-provider'; import { useSearchParams } from '../SearchParams'; -const Context = createContext({}); +const Context = createContext(''); -export const LocaleProvider = ({ children }) => { +export const LocaleProvider: React.FC = ({ children }) => { const { localization } = useConfig(); const defaultLocale = (localization && localization.defaultLocale) ? localization.defaultLocale : 'en'; - const [locale, setLocale] = useState(defaultLocale); + const [locale, setLocale] = useState(defaultLocale); const searchParams = useSearchParams(); const localeFromParams = searchParams.locale; useEffect(() => { - if (localeFromParams && localization.locales.indexOf(localeFromParams) > -1) setLocale(localeFromParams); + if (localeFromParams && localization.locales.indexOf(localeFromParams as string) > -1) setLocale(localeFromParams as string); }, [localeFromParams, localization]); return ( @@ -25,7 +25,7 @@ export const LocaleProvider = ({ children }) => { ); }; -export const useLocale = () => useContext(Context); +export const useLocale = (): string => useContext(Context); LocaleProvider.propTypes = { children: PropTypes.oneOfType([ diff --git a/src/admin/components/utilities/Meta/index.tsx b/src/admin/components/utilities/Meta/index.tsx index b7c96c0472..94910d0a0d 100644 --- a/src/admin/components/utilities/Meta/index.tsx +++ b/src/admin/components/utilities/Meta/index.tsx @@ -13,9 +13,9 @@ const Meta: React.FC = ({ keywords = 'CMS, Admin, Dashboard', }) => { const config = useConfig(); - const titleSuffix = config?.admin?.meta?.titleSuffix ?? '- Payload'; - const favicon = config?.admin?.meta?.favicon ?? payloadFavicon; - const ogImage = config?.admin?.meta?.ogImage ?? payloadOgImage; + const titleSuffix = config.admin.meta?.titleSuffix ?? '- Payload'; + const favicon = config.admin.meta.favicon ?? payloadFavicon; + const ogImage = config.admin.meta.ogImage ?? payloadOgImage; return ( ReactDOM.createPortal(children, document.getElementById('portal')); +const Portal = ({ children }: { children: React.ReactNode}): React.ReactPortal => ReactDOM.createPortal(children, document.getElementById('portal')); export default Portal; diff --git a/src/admin/components/utilities/RenderCustomComponent/index.tsx b/src/admin/components/utilities/RenderCustomComponent/index.tsx index 6f0cd7cac5..efa60f698c 100644 --- a/src/admin/components/utilities/RenderCustomComponent/index.tsx +++ b/src/admin/components/utilities/RenderCustomComponent/index.tsx @@ -1,7 +1,7 @@ import React from 'react'; -import PropTypes from 'prop-types'; +import { Props } from './types'; -const RenderCustomComponent = (props) => { +const RenderCustomComponent: React.FC = (props) => { const { CustomComponent, DefaultComponent, componentProps } = props; if (CustomComponent) { @@ -15,22 +15,4 @@ const RenderCustomComponent = (props) => { ); }; -RenderCustomComponent.defaultProps = { - path: undefined, - componentProps: {}, - CustomComponent: null, -}; - -RenderCustomComponent.propTypes = { - path: PropTypes.string, - DefaultComponent: PropTypes.oneOfType([ - PropTypes.shape({}), - PropTypes.func, - PropTypes.node, - PropTypes.element, - ]).isRequired, - CustomComponent: PropTypes.func, - componentProps: PropTypes.shape({}), -}; - export default RenderCustomComponent; diff --git a/src/admin/components/utilities/RenderCustomComponent/types.ts b/src/admin/components/utilities/RenderCustomComponent/types.ts new file mode 100644 index 0000000000..4908a5d63d --- /dev/null +++ b/src/admin/components/utilities/RenderCustomComponent/types.ts @@ -0,0 +1,7 @@ +import React from 'react'; + +export type Props = { + CustomComponent: React.ComponentType + DefaultComponent: React.ComponentType + componentProps?: unknown +} diff --git a/src/admin/components/utilities/SearchParams/index.tsx b/src/admin/components/utilities/SearchParams/index.tsx index 97c226cfc2..2d89485944 100644 --- a/src/admin/components/utilities/SearchParams/index.tsx +++ b/src/admin/components/utilities/SearchParams/index.tsx @@ -5,7 +5,7 @@ import qs from 'qs'; const Context = createContext({}); -export const SearchParamsProvider = ({ children }) => { +export const SearchParamsProvider: React.FC = ({ children }) => { const location = useLocation(); const params = qs.parse( @@ -27,4 +27,4 @@ SearchParamsProvider.propTypes = { ]).isRequired, }; -export const useSearchParams = () => useContext(Context); +export const useSearchParams = (): qs.ParsedQs => useContext(Context); diff --git a/src/admin/hooks/useDebounce.tsx b/src/admin/hooks/useDebounce.tsx index 51a1d0306d..d4ffae61f0 100644 --- a/src/admin/hooks/useDebounce.tsx +++ b/src/admin/hooks/useDebounce.tsx @@ -1,7 +1,7 @@ import { useState, useEffect } from 'react'; // Our hook -export default function useDebounce(value, delay) { +export default function useDebounce(value: unknown, delay: number): unknown { // State and setters for debounced value const [debouncedValue, setDebouncedValue] = useState(value); diff --git a/src/admin/hooks/useIntersect.tsx b/src/admin/hooks/useIntersect.tsx index b3ae43460c..c38cbe210d 100644 --- a/src/admin/hooks/useIntersect.tsx +++ b/src/admin/hooks/useIntersect.tsx @@ -1,8 +1,17 @@ /* eslint-disable no-shadow */ import { useEffect, useRef, useState } from 'react'; -export default ({ root = null, rootMargin, threshold = 0 } = {}) => { - const [entry, updateEntry] = useState({}); +type Intersect = [ + setNode: React.Dispatch, + entry: IntersectionObserverEntry +] + +const useIntersect = ({ + root = null, + rootMargin = '0px', + threshold = 0, +} = {}): Intersect => { + const [entry, updateEntry] = useState(); const [node, setNode] = useState(null); const observer = useRef( @@ -27,3 +36,5 @@ export default ({ root = null, rootMargin, threshold = 0 } = {}) => { return [setNode, entry]; }; + +export default useIntersect; diff --git a/src/admin/hooks/useMountEffect.tsx b/src/admin/hooks/useMountEffect.tsx index 655f74b59f..f6ac8434ae 100644 --- a/src/admin/hooks/useMountEffect.tsx +++ b/src/admin/hooks/useMountEffect.tsx @@ -1,5 +1,5 @@ import { useEffect } from 'react'; -const useMountEffect = func => useEffect(func, []); +const useMountEffect = (func: () => void): void => useEffect(func, []); export default useMountEffect; diff --git a/src/admin/hooks/usePayloadAPI.tsx b/src/admin/hooks/usePayloadAPI.tsx index 60f6204bdb..6343028681 100644 --- a/src/admin/hooks/usePayloadAPI.tsx +++ b/src/admin/hooks/usePayloadAPI.tsx @@ -3,11 +3,28 @@ import queryString from 'qs'; import { useLocale } from '../components/utilities/Locale'; import { requests } from '../api'; -const usePayloadAPI = (url, options = {}) => { +type Result = [ + { + isLoading: boolean + isError: boolean + data: unknown + }, + { + setParams: React.Dispatch + } +] + +type Options = { + initialParams?: unknown + initialData?: unknown +} + +type UsePayloadAPI = (url: string, options?: Options) => Result; + +const usePayloadAPI: UsePayloadAPI = (url, options = {}) => { const { initialParams = {}, initialData = {}, - onLoad, } = options; const [data, setData] = useState(initialData); @@ -18,8 +35,8 @@ const usePayloadAPI = (url, options = {}) => { const search = queryString.stringify({ locale, - ...params, - }, { depth: 10 }); + ...(typeof params === 'object' ? params : {}), + }); useEffect(() => { const fetchData = async () => { @@ -48,7 +65,7 @@ const usePayloadAPI = (url, options = {}) => { setIsError(false); setIsLoading(false); } - }, [url, locale, search, onLoad]); + }, [url, locale, search]); return [{ data, isLoading, isError }, { setParams }]; }; diff --git a/src/admin/hooks/useThrottledEffect.tsx b/src/admin/hooks/useThrottledEffect.tsx index 440988eac4..79d1125b7e 100644 --- a/src/admin/hooks/useThrottledEffect.tsx +++ b/src/admin/hooks/useThrottledEffect.tsx @@ -1,7 +1,9 @@ /* eslint-disable react-hooks/exhaustive-deps */ import { useEffect, useRef } from 'react'; -const useThrottledEffect = (callback, delay, deps = []) => { +type useThrottledEffect = (callback: React.EffectCallback, delay: number, deps: React.DependencyList) => void; + +const useThrottledEffect: useThrottledEffect = (callback, delay, deps = []) => { const lastRan = useRef(Date.now()); useEffect( diff --git a/src/admin/hooks/useTitle.tsx b/src/admin/hooks/useTitle.tsx index 6d29cc327e..4863e9460c 100644 --- a/src/admin/hooks/useTitle.tsx +++ b/src/admin/hooks/useTitle.tsx @@ -1,6 +1,6 @@ import { useFormFields } from '../components/forms/Form/context'; -const useTitle = (useAsTitle) => { +const useTitle = (useAsTitle: string): string => { const { getField } = useFormFields(); const titleField = getField(useAsTitle); return titleField?.value; diff --git a/src/admin/hooks/useUnmountEffect.tsx b/src/admin/hooks/useUnmountEffect.tsx index 5ae99d6902..597bbd49f4 100644 --- a/src/admin/hooks/useUnmountEffect.tsx +++ b/src/admin/hooks/useUnmountEffect.tsx @@ -1,6 +1,6 @@ import { useEffect } from 'react'; // eslint-disable-next-line react-hooks/exhaustive-deps -const useUnmountEffect = (callback) => useEffect(() => callback, []); +const useUnmountEffect = (callback: React.EffectCallback): void => useEffect(() => callback, []); export default useUnmountEffect; diff --git a/src/bin/build.ts b/src/bin/build.ts index bdf46f9e44..4b4d0a7416 100755 --- a/src/bin/build.ts +++ b/src/bin/build.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable global-require */ /* eslint-disable import/no-dynamic-require */ @@ -5,14 +6,31 @@ import webpack from 'webpack'; import getWebpackProdConfig from '../webpack/getWebpackProdConfig'; import findConfig from '../config/find'; import loadConfig from '../config/load'; -import { buildConfig } from '../config/build'; +import getBabelConfig from '../babel.config'; + +const babelConfig = getBabelConfig({ + env: () => false, +}); const configPath = findConfig(); -const build = () => { +const build = (): void => { try { - const unsanitizedConfig = loadConfig(); - const config = buildConfig(unsanitizedConfig); + require('@babel/register')({ + ...babelConfig, + extensions: ['.js', '.jsx', '.ts', '.tsx'], + plugins: [ + [ + require('babel-plugin-ignore-html-and-css-imports'), + { + removeExtensions: ['.svg', '.css', '.scss', '.png', '.jpg'], + }, + ], + ...babelConfig.plugins, + ], + }); + + const config = loadConfig(); const webpackProdConfig = getWebpackProdConfig({ ...config, diff --git a/src/bin/index.ts b/src/bin/index.ts index 63c830000a..5952749e61 100755 --- a/src/bin/index.ts +++ b/src/bin/index.ts @@ -1,5 +1,3 @@ -#!/usr/bin/env node - import minimist from 'minimist'; import build from './build'; diff --git a/src/collections/config/types.ts b/src/collections/config/types.ts index 2e03cb5c90..04f3440794 100644 --- a/src/collections/config/types.ts +++ b/src/collections/config/types.ts @@ -158,3 +158,16 @@ export type AfterForgotPasswordHook = (args?: { }) => any; export type AfterErrorHook = (args?: { [p: string]: any }, response?: any) => any; + +export type PaginatedDocs = { + docs: unknown[] + totalDocs: number + limit: number + totalPages: number + page: number + pagingCounter: number + hasPrevPage: boolean + hasNextPage: boolean + prevPage: number | null + nextPage: number | null +} diff --git a/src/config/find.ts b/src/config/find.ts index 7369ca6187..da6f2f0a36 100644 --- a/src/config/find.ts +++ b/src/config/find.ts @@ -1,5 +1,5 @@ import path from 'path'; -import fs from 'fs'; +import findUp from 'find-up'; const findConfig = (): string => { // If the developer has specified a config path, @@ -12,30 +12,21 @@ const findConfig = (): string => { return path.resolve(process.cwd(), process.env.PAYLOAD_CONFIG_PATH); } - // By default, Payload is installed as a node_module. - // Traverse up three levels and check for config - const defaultPath = path.resolve(__dirname, '../../../payload.config.js'); + const configPath = findUp.sync((dir) => { + const tsPath = path.join(dir, 'payload.config.ts'); + const hasTS = findUp.sync.exists(tsPath); - if (fs.existsSync(defaultPath)) { - return defaultPath; - } + if (hasTS) return tsPath; - const defaultTSPath = path.resolve(__dirname, '../../../payload.config.ts'); + const jsPath = path.join(dir, 'payload.config.js'); + const hasJS = findUp.sync.exists(jsPath); - if (fs.existsSync(defaultTSPath)) { - return defaultTSPath; - } + if (hasJS) return jsPath; - // Check for config in current working directory - const cwdJSPath = path.resolve(process.cwd(), 'payload.config.js'); - if (fs.existsSync(cwdJSPath)) { - return cwdJSPath; - } + return undefined; + }); - const cwdTSPath = path.resolve(process.cwd(), 'payload.config.ts'); - if (fs.existsSync(cwdTSPath)) { - return cwdTSPath; - } + if (configPath) return configPath; throw new Error('Error: cannot find Payload config. Please create a configuration file located at the root of your current working directory called "payload.config.js" or "payload.config.ts".'); }; diff --git a/src/config/types.ts b/src/config/types.ts index db39272ce9..60e79ba04a 100644 --- a/src/config/types.ts +++ b/src/config/types.ts @@ -57,6 +57,9 @@ export type PayloadConfig = { } disable?: boolean; indexHTML?: string; + components?: { + Nav: React.ComponentType + } }; collections?: PayloadCollectionConfig[]; globals?: Global[]; @@ -93,7 +96,8 @@ export type PayloadConfig = { }; }; localization?: { - locales: string[]; + locales: string[] + defaultLocale: string }; defaultLocale?: string; fallback?: boolean; diff --git a/src/fields/config/types.ts b/src/fields/config/types.ts index b3e605e6ef..298b15c958 100644 --- a/src/fields/config/types.ts +++ b/src/fields/config/types.ts @@ -39,7 +39,7 @@ type FieldBase = { readOnly?: boolean; disabled?: boolean; condition?: (...args: any[]) => any | void; - components?: { [key: string]: JSX.Element | (() => JSX.Element) }; + components?: { [key: string]: React.ComponentType }; }; access?: { create?: Access; @@ -52,6 +52,7 @@ type FieldBase = { } export type StandardField = FieldBase & { + type: string; fields?: Field[]; } @@ -120,6 +121,7 @@ export type RadioField = FieldBase & { value: string; label: string; }[]; + hasMany?: boolean; } export type Block = { @@ -135,23 +137,16 @@ export type BlockField = FieldBase & { type: 'blocks'; minRows?: number; maxRows?: number; - blocks?: Block[]; + blocks?: Field[]; }; -export type Field = NumberField - | TextField - | EmailField - | TextareaField - | CodeField - | CheckboxField - | DateField +export type Field = + | StandardField | BlockField | RadioField | RelationshipField | ArrayField | RichTextField - | GroupField - | RowField | SelectField | SelectManyField | UploadField; diff --git a/src/mongoose/buildSchema.ts b/src/mongoose/buildSchema.ts index 5a8a13697f..cbbd16e6b7 100644 --- a/src/mongoose/buildSchema.ts +++ b/src/mongoose/buildSchema.ts @@ -1,15 +1,17 @@ /* eslint-disable no-use-before-define */ import { Schema } from 'mongoose'; import { MissingFieldInputOptions } from '../errors'; -import { ArrayField, BlockField, CheckboxField, CodeField, DateField, EmailField, Field, GroupField, NumberField, RadioField, RelationshipField, RichTextField, RowField, SelectField, TextareaField, TextField, UploadField } from '../fields/config/types'; +import { ArrayField, BlockField, Field, RadioField, RelationshipField, SelectField, StandardField, UploadField } from '../fields/config/types'; const setBlockDiscriminators = (fields: Field[], schema) => { fields.forEach((field) => { - if (field.type === 'blocks' && field.blocks && field.blocks.length > 0) { - field.blocks.forEach((block) => { + const blockFieldType = field as BlockField; + if (blockFieldType.type === 'blocks' && blockFieldType.blocks && blockFieldType.blocks.length > 0) { + blockFieldType.blocks.forEach((blockItem: StandardField) => { let blockSchemaFields = {}; - block.fields.forEach((blockField) => { + // TODO: Would this blow up on a relationship since it doesn't have fields? + blockItem.fields.forEach((blockField) => { const fieldSchema = fieldToSchemaMap[blockField.type]; if (fieldSchema) { blockSchemaFields = fieldSchema(blockField, blockSchemaFields); @@ -17,9 +19,9 @@ const setBlockDiscriminators = (fields: Field[], schema) => { }); const blockSchema = new Schema(blockSchemaFields, { _id: false }); - schema.path(field.name).discriminator(block.slug, blockSchema); + schema.path(field.name).discriminator(blockItem.slug, blockSchema); - setBlockDiscriminators(block.fields, blockSchema); + setBlockDiscriminators(blockItem.fields, blockSchema); }); } }); @@ -58,27 +60,27 @@ const buildSchema = (configFields: Field[], options = {}): Schema => { }; const fieldToSchemaMap = { - number: (field: NumberField, fields: Field[]) => ({ + number: (field: Field, fields: Field[]) => ({ ...fields, [field.name]: { ...formatBaseSchema(field), type: Number }, }), - text: (field: TextField, fields: Field[]) => ({ + text: (field: Field, fields: Field[]) => ({ ...fields, [field.name]: { ...formatBaseSchema(field), type: String }, }), - email: (field: EmailField, fields: Field[]) => ({ + email: (field: Field, fields: Field[]) => ({ ...fields, [field.name]: { ...formatBaseSchema(field), type: String }, }), - textarea: (field: TextareaField, fields: Field[]) => ({ + textarea: (field: Field, fields: Field[]) => ({ ...fields, [field.name]: { ...formatBaseSchema(field), type: String }, }), - richText: (field: RichTextField, fields: Field[]) => ({ + richText: (field: Field, fields: Field[]) => ({ ...fields, [field.name]: { ...formatBaseSchema(field), type: Schema.Types.Mixed }, }), - code: (field: CodeField, fields: Field[]) => ({ + code: (field: Field, fields: Field[]) => ({ ...fields, [field.name]: { ...formatBaseSchema(field), type: String }, }), @@ -101,11 +103,11 @@ const fieldToSchemaMap = { [field.name]: field.hasMany ? [schema] : schema, // TODO: radio group with hasMany?? }; }, - checkbox: (field: CheckboxField, fields: Field[]) => ({ + checkbox: (field: Field, fields: Field[]) => ({ ...fields, [field.name]: { ...formatBaseSchema(field), type: Boolean }, }), - date: (field: DateField, fields: Field[]) => ({ + date: (field: Field, fields: Field[]) => ({ ...fields, [field.name]: { ...formatBaseSchema(field), type: Date }, }), @@ -147,10 +149,10 @@ const fieldToSchemaMap = { [field.name]: schema, }; }, - row: (field: RowField, fields: Field[]) => { + row: (field: StandardField, fields: Field[]) => { const newFields = { ...fields }; - field.fields.forEach((rowField) => { + field.fields.forEach((rowField: Field) => { const fieldSchemaMap = fieldToSchemaMap[rowField.type]; if (fieldSchemaMap) { @@ -172,7 +174,7 @@ const fieldToSchemaMap = { }, }; }, - group: (field: GroupField, fields: Field[]) => { + group: (field: StandardField, fields: Field[]) => { const schema = buildSchema(field.fields, { _id: false, id: false }); return { diff --git a/src/types/assets/index.d.ts b/src/types/assets/index.d.ts deleted file mode 100644 index 67591d0000..0000000000 --- a/src/types/assets/index.d.ts +++ /dev/null @@ -1,22 +0,0 @@ -declare module '*.svg' { - import React = require('react'); - - export const ReactComponent: React.SFC>; - const src: string; - export default src; -} - -declare module '*.jpg' { - const content: string; - export default content; -} - -declare module '*.png' { - const content: string; - export default content; -} - -declare module '*.json' { - const content: string; - export default content; -} diff --git a/src/utilities/asyncSome.ts b/src/utilities/asyncSome.ts new file mode 100644 index 0000000000..9deb2e73e3 --- /dev/null +++ b/src/utilities/asyncSome.ts @@ -0,0 +1,56 @@ +/* eslint-disable no-use-before-define */ +/* eslint-disable consistent-return */ +import wrappy from 'wrappy'; +import asap from 'asap'; + +type Reduce = (er: boolean, result: unknown) => void; +type Callback = (last: unknown, next: unknown) => void; + +const ensureFutureTick = wrappy((cb: Callback) => { + let sync = true; + asap(() => { + sync = false; + }); + + return function safe(...args: unknown[]) { + if (sync) { + asap(() => { + cb.apply(this, args); + }); + } else { cb.apply(this, args); } + }; +}); + +function some(list: unknown[], predicate: (item: unknown, reduce: Reduce) => void, cb: Callback): void { + const array = slice(list); + let index = 0; + const { length } = array; + const hecomes = ensureFutureTick(cb); + + + const reduce: Reduce = (er, result) => { + if (er) return hecomes(er, false); + if (result) return hecomes(null, result); + + index += 1; + map(); + }; + + map(); + + function map() { + if (index >= length) return hecomes(null, false); + + predicate(array[index], reduce); + } +} + +function slice(args: unknown[]) { + const l = args.length; + const a = []; + let i: number; + for (i = 0; i < l; i += 1) a[i] = args[i]; + return a; +} + +export default some; diff --git a/src/webpack/getWebpackDevConfig.ts b/src/webpack/getWebpackDevConfig.ts index d1d17ff768..a81b23f0c0 100644 --- a/src/webpack/getWebpackDevConfig.ts +++ b/src/webpack/getWebpackDevConfig.ts @@ -74,7 +74,6 @@ export default (config: PayloadConfig): Configuration => { crypto: false, https: false, http: false, - assert: false, }, modules: ['node_modules', path.resolve(__dirname, '../../node_modules')], alias: { diff --git a/src/webpack/getWebpackProdConfig.ts b/src/webpack/getWebpackProdConfig.ts index c6aee75e04..93757c134a 100644 --- a/src/webpack/getWebpackProdConfig.ts +++ b/src/webpack/getWebpackProdConfig.ts @@ -1,14 +1,14 @@ import HtmlWebpackPlugin from 'html-webpack-plugin'; import TerserJSPlugin from 'terser-webpack-plugin'; import MiniCSSExtractPlugin from 'mini-css-extract-plugin'; -import OptimizeCSSAssetsPlugin from 'optimize-css-assets-webpack-plugin'; +import CssMinimizerPlugin from 'css-minimizer-webpack-plugin'; import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; import path from 'path'; import webpack, { Configuration } from 'webpack'; import { Config } from '../config/types'; import babelConfig from '../babel.config'; -const mockModulePath = path.resolve(__dirname, '../mocks/emptyModule.js'); +const mockModulePath = path.resolve(__dirname, './mocks/emptyModule.js'); export default (config: Config): Configuration => { let webpackConfig: Configuration = { @@ -25,7 +25,7 @@ export default (config: Config): Configuration => { devtool: 'source-map', stats: 'errors-only', optimization: { - minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})], + minimizer: [new TerserJSPlugin({}), new CssMinimizerPlugin()], splitChunks: { cacheGroups: { styles: { @@ -41,53 +41,40 @@ export default (config: Config): Configuration => { module: { rules: [ { - test: /\.js$/, + test: /\.(t|j|)sx?$/, exclude: /node_modules[\\/](?!(@payloadcms[\\/]payload)[\\/]).*/, use: { loader: require.resolve('babel-loader'), options: babelConfig({ env: () => false }), }, }, + + { + test: /\.(sa|sc|c)ss$/, + sideEffects: true, + use: [ + MiniCSSExtractPlugin.loader, + require.resolve('css-loader'), + { + loader: require.resolve('postcss-loader'), + options: { + postcssOptions: { + plugins: [require.resolve('postcss-preset-env')], + }, + }, + }, + require.resolve('sass-loader'), + ], + }, { oneOf: [ { - test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/], - loader: require.resolve('url-loader'), - options: { - limit: 10000, - name: 'static/media/[name].[hash:8].[ext]', - }, + test: /\.(?:ico|gif|png|jpg|jpeg)$/i, + type: 'asset/resource', }, { - test: /\.(sa|sc|c)ss$/, - sideEffects: true, - use: [ - MiniCSSExtractPlugin.loader, - require.resolve('css-loader'), - { - loader: require.resolve('postcss-loader'), - options: { - postcssOptions: { - plugins: [ - [ - require.resolve('postcss-preset-env'), - { - // Options - }, - ], - ], - }, - }, - }, - require.resolve('sass-loader'), - ], - }, - { - exclude: [/\.(js|jsx|mjs)$/, /\.html$/, /\.json$/], - loader: require.resolve('file-loader'), - options: { - name: 'static/media/[name].[hash:8].[ext]', - }, + test: /\.(woff(2)?|eot|ttf|otf|svg|)$/, + type: 'asset/inline', }, ], }, @@ -99,20 +86,23 @@ export default (config: Config): Configuration => { crypto: false, https: false, http: false, - assert: false, }, modules: ['node_modules', path.resolve(__dirname, '../../node_modules')], alias: { 'payload/config': config.paths.config, '@payloadcms/payload$': mockModulePath, }, + extensions: ['.ts', '.tsx', '.js', '.json'], }, plugins: [ + new webpack.ProvidePlugin( + { process: 'process/browser' }, + ), new HtmlWebpackPlugin({ template: config.admin && config.admin.indexHTML ? path.join(config.paths.configDir, config.admin.indexHTML) : path.resolve(__dirname, '../admin/index.html'), - filename: './index.html', + filename: path.normalize('./index.html'), }), new webpack.DefinePlugin(Object.entries(config.publicENV).reduce((values, [key, val]) => ({ ...values, @@ -142,7 +132,7 @@ export default (config: Config): Configuration => { } if (config.webpack && typeof config.webpack === 'function') { - webpackConfig = config.webpack(webpackConfig, 'production'); + webpackConfig = config.webpack(webpackConfig); } return webpackConfig; diff --git a/tsconfig.json b/tsconfig.json index 89b1ac9c11..791acc1fee 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -15,19 +15,21 @@ "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ "baseUrl": "", "paths": { - "payload/config": [ - "src/admin/types/config" // Webpack alias to user config + "@payloadcms/payload/config": [ + "src/config/types.ts" ], + "@payloadcms/payload/auth": [ + "src/auth/types.ts" + ], + "@payloadcms/payload/types": [ + "src/types/index.ts" + ] }, "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ "resolveJsonModule": true, "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ "skipLibCheck": true, /* Skip type checking of declaration files. */ "forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */ - // "typeRoots": [ - // "./src", - // "./node_modules/@types" - // ] }, "include": [ "src/" @@ -38,6 +40,6 @@ "build", "src/tests", "src/tests/**/*.spec.ts", - // "node_modules/" + "node_modules" ] } diff --git a/yarn.lock b/yarn.lock index 16cf23319a..7e75c7ac9c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1360,10 +1360,10 @@ dependencies: mkdirp "^1.0.4" -"@payloadcms/config-provider@0.0.7": - version "0.0.7" - resolved "https://registry.yarnpkg.com/@payloadcms/config-provider/-/config-provider-0.0.7.tgz#c225f29cf1737e039c95bd54ba25be5e32550ae1" - integrity sha512-qiiz5i/BRPkU6wyBg01Cf5pikfYxudanIjONdpTx7Z4xaUN67OZ0SDCfRno5LGrUupsFgxlEfSIXFGWb9h4gdw== +"@payloadcms/config-provider@0.0.9": + version "0.0.9" + resolved "https://registry.yarnpkg.com/@payloadcms/config-provider/-/config-provider-0.0.9.tgz#b2f89bb64418b96c04ff8e08a7d39f82eb6fa281" + integrity sha512-M8Lgp7tw0uIIKSJ5MjLsP3yS5406cmUEWtdnH/zshq3uRNGYmvlg/hOmFl0pJpZdut9An+qCFVhvjSTaQAok/Q== "@popperjs/core@^2.4.4": version "2.5.4" @@ -1446,6 +1446,11 @@ resolved "https://registry.yarnpkg.com/@types/aria-query/-/aria-query-4.2.0.tgz#14264692a9d6e2fa4db3df5e56e94b5e25647ac0" integrity sha512-iIgQNzCm0v7QMhhe4Jjn9uRh+I6GoPmt03CbEtwx3ao8/EfoQcmgtqH4vQ5Db/lxiIGaWDv6nwvunuh0RyX0+A== +"@types/asap@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@types/asap/-/asap-2.0.0.tgz#d529e9608c83499a62ae08c871c5e62271aa2963" + integrity sha512-upIS0Gt9Mc8eEpCbYMZ1K8rhNosfKUtimNcINce+zLwJF5UpM3Vv7yz3S5l/1IX+DxTa8lTkUjqynvjRXyJzsg== + "@types/autoprefixer@^9.7.2": version "9.7.2" resolved "https://registry.yarnpkg.com/@types/autoprefixer/-/autoprefixer-9.7.2.tgz#64b3251c9675feef5a631b7dd34cfea50a8fdbcc" @@ -1639,6 +1644,13 @@ dependencies: "@types/webpack" "*" +"@types/find-up@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/find-up/-/find-up-4.0.0.tgz#6b74a76670477a23f0793cfaf2dafc86df59723a" + integrity sha512-QlRNKeOPFWKisbNtKVOOGXw3AeLbkw8UmT/EyEGM6brfqpYffKBcch7f1y40NYN9O90aK2+K0xBMDJfOAsg2qg== + dependencies: + find-up "*" + "@types/graceful-fs@^4.1.2": version "4.1.4" resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.4.tgz#4ff9f641a7c6d1a3508ff88bc3141b152772e753" @@ -1806,6 +1818,14 @@ "@types/mongodb" "*" "@types/node" "*" +"@types/node-fetch@^2.5.7": + version "2.5.7" + resolved "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.7.tgz#20a2afffa882ab04d44ca786449a276f9f6bbf3c" + integrity sha512-o2WVNf5UhWRkxlf6eq+jMZDu7kjgpgJfl4xVNlvryc95O/6F2ld8ztKX+qu+Rjyet93WAWm5LjeX9H5FGkODvw== + dependencies: + "@types/node" "*" + form-data "^3.0.0" + "@types/node-sass@^4.11.1": version "4.11.1" resolved "https://registry.yarnpkg.com/@types/node-sass/-/node-sass-4.11.1.tgz#bda27c5181cbf7c090c3058e119633dfb2b6504c" @@ -2840,7 +2860,7 @@ array.prototype.flatmap@^1.2.3: es-abstract "^1.18.0-next.1" function-bind "^1.1.1" -asap@^2.0.0: +asap@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= @@ -2887,13 +2907,6 @@ async-limiter@~1.0.0: resolved "https://registry.yarnpkg.com/async-limiter/-/async-limiter-1.0.1.tgz#dd379e94f0db8310b08291f9d64c3209766617fd" integrity sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ== -async-some@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/async-some/-/async-some-1.0.2.tgz#4d8a81620d5958791b5b98f802d3207776e95509" - integrity sha1-TYqBYg1ZWHkbW5j4AtMgd3bpVQk= - dependencies: - dezalgo "^1.0.2" - asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -4083,6 +4096,21 @@ css-loader@^5.0.1: schema-utils "^3.0.0" semver "^7.3.2" +css-minimizer-webpack-plugin@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-1.1.5.tgz#f6f41358518d0f28b7a2d6819dfe1e410bc404f6" + integrity sha512-mXgaoFjNpIudZfxD49N1aPtLxfXGJt+BVPVjQ+H66I48b5n4wJtFpYfffVr7izK8W6fD01J7K0kUcP6HGjw90w== + dependencies: + cacache "^15.0.5" + cssnano "^4.1.10" + find-cache-dir "^3.3.1" + jest-worker "^26.3.0" + p-limit "^3.0.2" + schema-utils "^3.0.0" + serialize-javascript "^5.0.1" + source-map "^0.6.1" + webpack-sources "^1.4.3" + css-prefers-color-scheme@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/css-prefers-color-scheme/-/css-prefers-color-scheme-3.1.1.tgz#6f830a2714199d4f0d0d0bb8a27916ed65cff1f4" @@ -4468,14 +4496,6 @@ detect-newline@^3.0.0: resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== -dezalgo@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" - integrity sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY= - dependencies: - asap "^2.0.0" - wrappy "1" - dicer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.3.0.tgz#eacd98b3bfbf92e8ab5c2fdb71aaac44bb06b872" @@ -5399,6 +5419,14 @@ find-root@^1.1.0: resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.1.0.tgz#abcfc8ba76f708c42a97b3d685b7e9450bfb9ce4" integrity sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng== +find-up@*, find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + find-up@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" @@ -7079,7 +7107,7 @@ jest-watcher@^26.6.2: jest-util "^26.6.2" string-length "^4.0.1" -jest-worker@^26.5.0, jest-worker@^26.6.1, jest-worker@^26.6.2: +jest-worker@^26.3.0, jest-worker@^26.5.0, jest-worker@^26.6.1, jest-worker@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== @@ -7328,14 +7356,6 @@ language-tags@^1.0.5: dependencies: language-subtag-registry "~0.3.2" -last-call-webpack-plugin@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz#9742df0e10e3cf46e5c0381c2de90d3a7a2d7555" - integrity sha512-7KI2l2GIZa9p2spzPIVZBYyNKkN+e/SQPpnjlTiPhdbDW3F86tdKKELxKpzJ5sgU19wQWsACULZmpTPYHeWO5w== - dependencies: - lodash "^4.17.5" - webpack-sources "^1.1.0" - latest-version@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-3.1.0.tgz#a205383fea322b33b5ae3b18abee0dc2f356ee15" @@ -7433,6 +7453,13 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + lockfile@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/lockfile/-/lockfile-1.0.4.tgz#07f819d25ae48f87e538e6578b6964a4981a5609" @@ -7515,7 +7542,7 @@ lodash.uniq@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash@^4.0.0, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.4, lodash@^4.17.5, lodash@~4.17.10: +lodash@^4.0.0, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.4, lodash@~4.17.10: version "4.17.20" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== @@ -8447,14 +8474,6 @@ opener@^1.5.1: resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A== -optimize-css-assets-webpack-plugin@^5.0.4: - version "5.0.4" - resolved "https://registry.yarnpkg.com/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-5.0.4.tgz#85883c6528aaa02e30bbad9908c92926bb52dc90" - integrity sha512-wqd6FdI2a5/FdoiCNNkEvLeA//lHHfG24Ln2Xm2qqdIk4aOlsR18jwpyOihqQ8849W3qu2DX8fOYxpvTMj+93A== - dependencies: - cssnano "^4.1.10" - last-call-webpack-plugin "^3.0.0" - optionator@^0.8.1, optionator@^0.8.3: version "0.8.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" @@ -8542,6 +8561,13 @@ p-locate@^4.1.0: dependencies: p-limit "^2.2.0" +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + p-map@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" @@ -12442,7 +12468,7 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrappy@1: +wrappy@1, wrappy@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=