diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 0000000..1a3ff48 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,3 @@ +.next +node_modules +*.json diff --git a/.eslintrc.json b/.eslintrc.json index bffb357..f6f385f 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,3 +1,62 @@ { - "extends": "next/core-web-vitals" + "plugins": ["unused-imports", "@typescript-eslint"], + "extends": ["next/core-web-vitals", "plugin:@typescript-eslint/recommended"], + "parserOptions": { + "project": ["./tsconfig.json", "./tsconfig.test.json"], + "extraFileExtensions": [".json"] + }, + "rules": { + "@typescript-eslint/no-non-null-assertion": "error", + "no-trailing-spaces": "error", + "no-unused-vars": "off", + "unused-imports/no-unused-imports": "error", + "unused-imports/no-unused-vars": "off", + "@typescript-eslint/no-unused-vars": [ + "error", + { "args": "after-used", "argsIgnorePattern": "^_$" } + ], + "@typescript-eslint/no-explicit-any": "error", + "@typescript-eslint/member-delimiter-style": [ + "error", + { + "multiline": { + "delimiter": "none", + "requireLast": false + }, + "singleline": { + "delimiter": "comma", + "requireLast": false + } + } + ], + "@typescript-eslint/semi": ["error", "never"], + "no-shadow": "off", + "@typescript-eslint/no-shadow": ["error"], + "no-useless-constructor": "off", + "no-use-before-define": "off", + "jsx-a11y/label-has-associated-control": "error", + "no-console": ["error", { "allow": ["warn", "error"] }], + "indent": [2, 2], + "new-cap": ["error", { "capIsNewExceptions": ["Router"] }], + "semi": ["error", "never"], + "multiline-ternary": "off", + "quotes": ["error", "single", { "avoidEscape": true }], + "jsx-quotes": ["error", "prefer-single"], + "no-return-await": "error", + "no-process-env": "error", + "react-hooks/exhaustive-deps": [ + "warn", + { + "additionalHooks": "(useAsyncEffect)" + } + ] + }, + "overrides": [ + { + "files": "**/*.js", + "rules": { + "@typescript-eslint/no-var-requires": ["off"] + } + } + ] } diff --git a/.lintstagedrc b/.lintstagedrc new file mode 100644 index 0000000..bda9efd --- /dev/null +++ b/.lintstagedrc @@ -0,0 +1,12 @@ +{ + "(!cypress)/**/*.+(ts|tsx)": [ + "tsc-files --noEmit" + ], + "**/*.{js,jsx,ts,tsx,json}": [ + "prettier --write --loglevel warn", + "eslint --fix" + ], + "**/*.{css,scss,less}": [ + "stylelint --fix" + ] +} diff --git a/.stylelintrc.json b/.stylelintrc.json new file mode 100644 index 0000000..caec3ed --- /dev/null +++ b/.stylelintrc.json @@ -0,0 +1,17 @@ +{ + "extends": ["stylelint-config-standard", "stylelint-config-idiomatic-order"], + "rules": { + "selector-pseudo-class-no-unknown": [ + true, + { + "ignorePseudoClasses": ["global"] + } + ], + "no-descending-specificity": null, + "indentation": 4, + "declaration-block-no-duplicate-properties": true, + "no-duplicate-selectors": true, + "selector-class-pattern": "^.*|([a-z][a-zA-Z0-9]+)$", + "custom-property-pattern": ".*" + } +} diff --git a/components/contexts/GroupProvider.tsx b/components/contexts/GroupProvider.tsx index 49973ee..e36e4a4 100644 --- a/components/contexts/GroupProvider.tsx +++ b/components/contexts/GroupProvider.tsx @@ -1,10 +1,14 @@ -import {createContext, FC, useCallback, useContext, useEffect, useMemo, useState} from "react"; -import {Group} from "../../src/types"; -import {ReactNodeLike} from "prop-types"; -import pako from "pako"; -import {Dict} from "../../src/types"; -import {fixedEncodeURIComponent} from "../../src/utils"; -import {GroupRenameBody, GroupSetFactoryArrayBody, SetFactoryArrayBody} from "../../src/types/ApiSchemasFrontend"; +import { createContext, FC, useCallback, useContext, useMemo, useState } from 'react' +import { Group } from '../../src/types' +import { ReactNodeLike } from 'prop-types' +import pako from 'pako' +import { Dict } from '../../src/types' +import { fixedEncodeURIComponent } from '../../src/utils' +import { + GroupRenameBody, + GroupSetFactoryArrayBody, + SetFactoryArrayBody +} from '../../src/types/ApiSchemasFrontend' interface Props { children: ReactNodeLike @@ -31,8 +35,8 @@ interface GroupContextType { removeGroup(name: string): void renameGroup(name: string, newName: string): void - setFactories(name: string, factories: string[], type: 'exports'|'malls'): void - getInputType(uid: string): 'base'|'produced'|'unknown' + setFactories(name: string, factories: string[], type: 'exports' | 'malls'): void + getInputType(uid: string): 'base' | 'produced' | 'unknown' store(): Uint8Array load(str: Uint8Array): void @@ -43,29 +47,47 @@ const defaultValues: GroupContextType = { exportedFactories: new Set(), ignoredFactories: [], - setIgnoredFactories() {}, + setIgnoredFactories() { + return + }, baseFactories: [], - setBaseFactories() {}, + setBaseFactories() { + return + }, groups: {}, - addGroup() {}, - removeGroup() {}, - renameGroup() {}, + addGroup() { + return + }, + removeGroup() { + return + }, + renameGroup() { + return + }, - setFactories() {}, - getInputType() {return 'unknown'}, + setFactories() { + return + }, + getInputType() { + return 'unknown' + }, - store() {return new Uint8Array(0)}, - load() {} + store() { + return new Uint8Array(0) + }, + load() { + return + } } -const GroupContext = createContext(defaultValues); +const GroupContext = createContext(defaultValues) export const useGroups = () => useContext(GroupContext) interface StoredFile { - groups: Dict, - basicValues: string[], + groups: Dict + basicValues: string[] excludedSuggestions: string[] } @@ -80,143 +102,203 @@ export const postFetchJson = async (url: string, body: Dict) => { return res.json() } -export const GroupProvider: FC = ({children, id, initial}) => { +export const GroupProvider: FC = ({ children, id, initial }) => { const [excludedSuggestions, _setExcludedSuggestions] = useState(initial.ignored) const [basicValues, _setBasicValues] = useState(initial.base) const [groups, setGroups] = useState>(initial.groups) const doNotSuggest = useMemo>(() => { - return new Set([...Object.values(groups).flatMap(group => [...group.exports, ...group.malls]), ...excludedSuggestions, ...basicValues]) + return new Set([ + ...Object.values(groups).flatMap(group => [...group.exports, ...group.malls]), + ...excludedSuggestions, + ...basicValues + ]) }, [basicValues, groups, excludedSuggestions]) const exportedFactories = useMemo>(() => { return new Set([...Object.values(groups).flatMap(group => [...group.exports])]) }, [groups]) - const setExcludedSuggestions = useCallback((val) => { - _setExcludedSuggestions(val) - postFetchJson(`/api/${fixedEncodeURIComponent(id)}/factories`, { - type: 'ignored', - factories: val - } as SetFactoryArrayBody) - .catch(console.error) - }, [id]) + const setExcludedSuggestions = useCallback( + val => { + _setExcludedSuggestions(val) + postFetchJson(`/api/${fixedEncodeURIComponent(id)}/factories`, { + type: 'ignored', + factories: val + } as SetFactoryArrayBody).catch(console.error) + }, + [id] + ) - const setBasicValues = useCallback((val) => { - _setBasicValues(val) - postFetchJson(`/api/${fixedEncodeURIComponent(id)}/factories`, { - type: 'base', - factories: val - } as SetFactoryArrayBody) - .catch(console.error) - }, [id]) + const setBasicValues = useCallback( + val => { + _setBasicValues(val) + postFetchJson(`/api/${fixedEncodeURIComponent(id)}/factories`, { + type: 'base', + factories: val + } as SetFactoryArrayBody).catch(console.error) + }, + [id] + ) - const addGroup = useCallback((name: string, exports: string[] = [], malls: string[] = []) => { - name = name.replace(/[.$]/g, '') - if (name in groups) return false - setGroups(groups => { - groups[name] = { name, exports, malls } - return {...groups} - }) - ;(async () => { - await postFetchJson(`/api/${fixedEncodeURIComponent(id)}/group/${fixedEncodeURIComponent(name)}/add`, {}) - if (exports.length) { - await postFetchJson(`/api/${fixedEncodeURIComponent(id)}/group/${fixedEncodeURIComponent(name)}/factories`, { - type: 'exports', - factories: exports - } as GroupSetFactoryArrayBody) - } - if (malls.length) { - await postFetchJson(`/api/${fixedEncodeURIComponent(id)}/group/${fixedEncodeURIComponent(name)}/factories`, { - type: 'malls', - factories: exports - } as GroupSetFactoryArrayBody) - } - })().catch(console.error) - return true - }, [groups, id]) - const removeGroup = useCallback((name: string) => { - name = name.replace(/[.$]/g, '') - setGroups(groups => { - delete groups[name] - console.log(groups[name]) - return {...groups} - }) - postFetchJson(`/api/${fixedEncodeURIComponent(id)}/group/${fixedEncodeURIComponent(name)}/remove`, {}) - .catch(console.error) - }, [id]) - const renameGroup = useCallback((name: string, newName: string) => { - name = name.replace(/[.$]/g, '') - newName = newName.replace(/[.$]/g, '') - if (newName in groups) return - setGroups(groups => { - groups[newName] = {...groups[name], name: newName} - delete groups[name] - return {...groups} - }) - postFetchJson(`/api/${fixedEncodeURIComponent(id)}/group/${fixedEncodeURIComponent(name)}/rename`, { - newName - } as GroupRenameBody) - .catch(console.error) - }, [groups, id]) + const addGroup = useCallback( + (name: string, exports: string[] = [], malls: string[] = []) => { + name = name.replace(/[.$]/g, '') + if (name in groups) return false + setGroups(g => { + g[name] = { name, exports, malls } + return { ...g } + }) + ;(async () => { + await postFetchJson( + `/api/${fixedEncodeURIComponent(id)}/group/${fixedEncodeURIComponent(name)}/add`, + {} + ) + if (exports.length) { + await postFetchJson( + `/api/${fixedEncodeURIComponent(id)}/group/${fixedEncodeURIComponent(name)}/factories`, + { + type: 'exports', + factories: exports + } as GroupSetFactoryArrayBody + ) + } + if (malls.length) { + await postFetchJson( + `/api/${fixedEncodeURIComponent(id)}/group/${fixedEncodeURIComponent(name)}/factories`, + { + type: 'malls', + factories: exports + } as GroupSetFactoryArrayBody + ) + } + })().catch(console.error) + return true + }, + [groups, id] + ) + const removeGroup = useCallback( + (name: string) => { + name = name.replace(/[.$]/g, '') + setGroups(g => { + delete g[name] + return { ...g } + }) + postFetchJson( + `/api/${fixedEncodeURIComponent(id)}/group/${fixedEncodeURIComponent(name)}/remove`, + {} + ).catch(console.error) + }, + [id] + ) + const renameGroup = useCallback( + (name: string, newName: string) => { + name = name.replace(/[.$]/g, '') + newName = newName.replace(/[.$]/g, '') + if (newName in groups) return + setGroups(g => { + g[newName] = { ...g[name], name: newName } + delete g[name] + return { ...g } + }) + postFetchJson( + `/api/${fixedEncodeURIComponent(id)}/group/${fixedEncodeURIComponent(name)}/rename`, + { + newName + } as GroupRenameBody + ).catch(console.error) + }, + [groups, id] + ) - const setFactories = useCallback((name: string, factories: string[], type: 'exports'|'malls') => { - name = name.replace(/[.$]/g, '') - setGroups(groups => { - groups[name] = {...groups[name], [type]: factories} - return {...groups} - }) - postFetchJson(`/api/${fixedEncodeURIComponent(id)}/group/${fixedEncodeURIComponent(name)}/factories`, { - type, - factories - } as GroupSetFactoryArrayBody) - .catch(console.error) - }, [id]) - const getInputType = useCallback((uid: string) => { - if (basicValues.includes(uid)) return 'base' - else if (exportedFactories.has(uid)) return 'produced' - else return 'unknown' - }, [basicValues, exportedFactories]) + const setFactories = useCallback( + (name: string, factories: string[], type: 'exports' | 'malls') => { + name = name.replace(/[.$]/g, '') + setGroups(g => { + g[name] = { ...g[name], [type]: factories } + return { ...g } + }) + postFetchJson( + `/api/${fixedEncodeURIComponent(id)}/group/${fixedEncodeURIComponent(name)}/factories`, + { + type, + factories + } as GroupSetFactoryArrayBody + ).catch(console.error) + }, + [id] + ) + const getInputType = useCallback( + (uid: string) => { + if (basicValues.includes(uid)) return 'base' + else if (exportedFactories.has(uid)) return 'produced' + else return 'unknown' + }, + [basicValues, exportedFactories] + ) const store = useCallback(() => { - const btoa = (bin: Uint8Array) => Buffer.from(bin).toString('base64') + // const btoa = (bin: Uint8Array) => Buffer.from(bin).toString('base64') const value: StoredFile = { - groups, basicValues, excludedSuggestions + groups, + basicValues, + excludedSuggestions } const uncompressed = JSON.stringify(value) return pako.deflate(uncompressed) }, [basicValues, excludedSuggestions, groups]) - const load = useCallback((compressed: Uint8Array) => { - const atob = (str: string) => Buffer.from(str, 'base64') - const uncompressed = pako.inflate(compressed, {to: "string"}) - const value: StoredFile = JSON.parse(uncompressed) - if (!value.groups || !value.basicValues || !value.excludedSuggestions) return - setGroups(value.groups) - setBasicValues(value.basicValues) - setExcludedSuggestions(value.excludedSuggestions) - }, []) + const load = useCallback( + (compressed: Uint8Array) => { + // const atob = (str: string) => Buffer.from(str, 'base64') + const uncompressed = pako.inflate(compressed, { to: 'string' }) + const value: StoredFile = JSON.parse(uncompressed) + if (!value.groups || !value.basicValues || !value.excludedSuggestions) return + setGroups(value.groups) + setBasicValues(value.basicValues) + setExcludedSuggestions(value.excludedSuggestions) + }, + [setBasicValues, setExcludedSuggestions] + ) - const value: GroupContextType = useMemo(() => ({ - doNotSuggest, - exportedFactories, + const value: GroupContextType = useMemo( + () => ({ + doNotSuggest, + exportedFactories, - ignoredFactories: excludedSuggestions, - setIgnoredFactories: setExcludedSuggestions, + ignoredFactories: excludedSuggestions, + setIgnoredFactories: setExcludedSuggestions, - baseFactories: basicValues, - setBaseFactories: setBasicValues, + baseFactories: basicValues, + setBaseFactories: setBasicValues, - groups, - addGroup, - removeGroup, - renameGroup, + groups, + addGroup, + removeGroup, + renameGroup, - setFactories, - getInputType, + setFactories, + getInputType, - store, - load - }), [addGroup, basicValues, doNotSuggest, excludedSuggestions, exportedFactories, getInputType, groups, load, removeGroup, renameGroup, setBasicValues, setExcludedSuggestions, setFactories, store]) + store, + load + }), + [ + addGroup, + basicValues, + doNotSuggest, + excludedSuggestions, + exportedFactories, + getInputType, + groups, + load, + removeGroup, + renameGroup, + setBasicValues, + setExcludedSuggestions, + setFactories, + store + ] + ) return {children} } diff --git a/components/home/EntityIcon/EntityIcon.module.css b/components/home/EntityIcon/EntityIcon.module.css index cf40e1b..d8ae2e0 100644 --- a/components/home/EntityIcon/EntityIcon.module.css +++ b/components/home/EntityIcon/EntityIcon.module.css @@ -1,5 +1,5 @@ .span { - background: #DDD; + background: #ddd; font-size: 2em; border: 1px solid white; display: inline-block; diff --git a/components/home/EntityIcon/EntityIcon.tsx b/components/home/EntityIcon/EntityIcon.tsx index c0cbc49..8be093a 100644 --- a/components/home/EntityIcon/EntityIcon.tsx +++ b/components/home/EntityIcon/EntityIcon.tsx @@ -1,18 +1,18 @@ -import {FC, HTMLProps, useMemo} from "react" -import {Entity} from "../../../src/types" -import {useFactories} from "../../../src/hooks/useFactories" +import { FC, HTMLProps, useMemo } from 'react' +import { Entity } from '../../../src/types' +import { useFactories } from '../../../src/hooks/useFactories' import styles from './EntityIcon.module.css' -import cx from "classnames"; +import cx from 'classnames' interface Props extends Omit, 'value'> { - value: Entity|string + value: Entity | string amount?: number } -export const EntityIcon: FC = ({className, value, amount, ...rest}) => { - const {findFactory} = useFactories() +export const EntityIcon: FC = ({ className, value, amount, ...rest }) => { + const { findFactory } = useFactories() const entity = useMemo(() => { - return typeof value === "object" + return typeof value === 'object' ? value : value === '/Time' ? { @@ -29,9 +29,15 @@ export const EntityIcon: FC = ({className, value, amount, ...rest}) => { } }, [findFactory, value]) - return - {/* eslint-disable-next-line @next/next/no-img-element */} - {entity.name}/ - {amount !== undefined && {amount}} - + return ( + + {/* eslint-disable-next-line @next/next/no-img-element */} + {entity.name} + {amount !== undefined && {amount}} + + ) } diff --git a/components/home/EntitySpan/EntitySpan.tsx b/components/home/EntitySpan/EntitySpan.tsx index be443ba..2be29ea 100644 --- a/components/home/EntitySpan/EntitySpan.tsx +++ b/components/home/EntitySpan/EntitySpan.tsx @@ -1,25 +1,33 @@ -import {FC, HTMLProps, memo, useMemo} from "react" -import {EnrichedEntity, Entity} from "../../../src/types" -import {useFactories} from "../../../src/hooks/useFactories" +import { FC, HTMLProps, memo, useMemo } from 'react' +import { EnrichedEntity } from '../../../src/types' +import { useFactories } from '../../../src/hooks/useFactories' import styles from './EntitySpan.module.css' -import {RecipeSpan} from "../Recipe/Recipe"; -import {LeftClickIcon} from "../LeftClickIcon/LeftClickIcon"; -import cx from 'classnames'; -import {EntityIcon} from "../EntityIcon/EntityIcon"; +import { RecipeSpan } from '../Recipe/Recipe' +import { LeftClickIcon } from '../LeftClickIcon/LeftClickIcon' +import cx from 'classnames' +import { EntityIcon } from '../EntityIcon/EntityIcon' interface Props extends Omit, 'value'> { - value: EnrichedEntity|string - state?: 'base'|'produced'|'unknown' + value: EnrichedEntity | string + state?: 'base' | 'produced' | 'unknown' leftClickText?: string rightClickText?: string simpleStyle?: boolean className?: string } -const EntitySpanUnmemo: FC = ({className, value, state, leftClickText, rightClickText, simpleStyle, ...rest}) => { - const {findFactory} = useFactories() +const EntitySpanUnmemo: FC = ({ + className, + value, + state, + leftClickText, + rightClickText, + simpleStyle, + ...rest +}) => { + const { findFactory } = useFactories() const entity = useMemo(() => { - return typeof value === "object" + return typeof value === 'object' ? value : findFactory(value) ?? { usedBy: [], @@ -30,34 +38,52 @@ const EntitySpanUnmemo: FC = ({className, value, state, leftClickText, ri } }, [findFactory, value]) - return - {/* eslint-disable-next-line @next/next/no-img-element */} - {entity.name}/ - {entity.name} -
- {entity.recipe && ( - <> -
Recipe
- - - )} - {entity.usedBy?.length ? ( - <> -
Used By
-
- {entity.usedBy.map(used => )} -
- - ) : null} - {(leftClickText || rightClickText) && ( - <> -
Actions
- {leftClickText &&
{leftClickText}
} - {rightClickText &&
{rightClickText}
} - - )} -
-
+ return ( + + {/* eslint-disable-next-line @next/next/no-img-element */} + {entity.name} + {entity.name} +
+ {entity.recipe && ( + <> +
Recipe
+ + + )} + {entity.usedBy?.length ? ( + <> +
Used By
+
+ {entity.usedBy.map(used => ( + + ))} +
+ + ) : null} + {(leftClickText || rightClickText) && ( + <> +
Actions
+ {leftClickText && ( +
+ {' '} + {leftClickText} +
+ )} + {rightClickText && ( +
+ {' '} + {rightClickText} +
+ )} + + )} +
+
+ ) } export const EntitySpan = memo(EntitySpanUnmemo) diff --git a/components/home/FactorySelect/FactorySelect.module.css b/components/home/FactorySelect/FactorySelect.module.css index 264b4fc..0d5fc0a 100644 --- a/components/home/FactorySelect/FactorySelect.module.css +++ b/components/home/FactorySelect/FactorySelect.module.css @@ -4,8 +4,7 @@ } .select :global(.factory-select__multi-value), - .select :global(.factory-select__menu) - { + .select :global(.factory-select__menu) { background-color: #444; } @@ -18,6 +17,6 @@ } .select :global(.factory-select__multi-value__label) { - color: #DDDDDD; + color: #dddddd; } } diff --git a/components/home/FactorySelect/FactorySelect.tsx b/components/home/FactorySelect/FactorySelect.tsx index 8cd987b..7aa66a4 100644 --- a/components/home/FactorySelect/FactorySelect.tsx +++ b/components/home/FactorySelect/FactorySelect.tsx @@ -1,9 +1,9 @@ -import {FC, memo, useEffect, useMemo, useState} from "react"; -import Select from "react-select"; -import {isNonNullable} from "../../../src/utils"; -import details from "../../../res/details.json"; -import styles from "./FactorySelect.module.css"; -import {EntitySpan} from "../EntitySpan/EntitySpan"; +import { FC, memo, useMemo } from 'react' +import Select from 'react-select' +import { isNonNullable } from '../../../src/utils' +import details from '../../../res/details.json' +import styles from './FactorySelect.module.css' +import { EntitySpan } from '../EntitySpan/EntitySpan' interface Props { id: string @@ -16,33 +16,37 @@ const options = details.map(detail => ({ value: detail.href })) -const FactorySelectBase: FC = ({id, factories, onSetFactories}) => { +const FactorySelectBase: FC = ({ id, factories, onSetFactories }) => { const state = useMemo(() => { return factories .map(factory => options.find(option => option.value === factory)) .filter(isNonNullable) }, [factories]) - return ( + + ), + Option: ({ innerProps, data }) => ( +
+ +
+ ) + }} + isMulti + options={options as never} + onChange={e => { + onSetFactories(e.map(s => s?.value)) + }} + className={styles.select} + classNamePrefix={'factory-select'} + /> + ) } export const FactorySelect = memo(FactorySelectBase) diff --git a/components/home/GroupBox/GroupBox.tsx b/components/home/GroupBox/GroupBox.tsx index 2cff42e..2623e80 100644 --- a/components/home/GroupBox/GroupBox.tsx +++ b/components/home/GroupBox/GroupBox.tsx @@ -1,14 +1,14 @@ -import {FC, memo, useCallback, useMemo, useState} from "react"; -import {FactorySelect} from "../FactorySelect/FactorySelect"; -import {useFactories} from "../../../src/hooks/useFactories"; -import {EnrichedEntity, Group} from "../../../src/types"; -import styles from "./GroupBox.module.css" -import {EntitySpan} from "../EntitySpan/EntitySpan"; -import {useGroups} from "../../contexts/GroupProvider"; -import {calculateInputs} from "../../../src/calculateInputs"; -import {fixedEncodeURIComponent, uniquify} from "../../../src/utils"; -import Link from "next/link"; -import {useRouter} from "next/router"; +import { FC, memo, useCallback, useMemo, useState } from 'react' +import { FactorySelect } from '../FactorySelect/FactorySelect' +import { useFactories } from '../../../src/hooks/useFactories' +import { EnrichedEntity, Group } from '../../../src/types' +import styles from './GroupBox.module.css' +import { EntitySpan } from '../EntitySpan/EntitySpan' +import { useGroups } from '../../contexts/GroupProvider' +import { calculateInputs } from '../../../src/calculateInputs' +import { fixedEncodeURIComponent, uniquify } from '../../../src/utils' +import Link from 'next/link' +import { useRouter } from 'next/router' interface Props { group: Group @@ -16,7 +16,7 @@ interface Props { const GroupBoxBase: FC = ({ group }) => { const router = useRouter() - const {factories, findFactory} = useFactories() + const { factories, findFactory } = useFactories() const { doNotSuggest, setFactories, @@ -28,24 +28,14 @@ const GroupBoxBase: FC = ({ group }) => { removeGroup, getInputType } = useGroups() - const { - name, - exports, - malls - } = group + const { name, exports, malls } = group const [isDeleteConfirm, setDeleteConfirm] = useState(false) const [inputs, intermediates] = useMemo(() => { const allProducingFactories = [...exports, ...malls] - return calculateInputs( - allProducingFactories, - ignoredFactories, - baseFactories, - exportedFactories, - findFactory - ) - }, [exports, malls, ignoredFactories, baseFactories, findFactory, exportedFactories]) + return calculateInputs(allProducingFactories, baseFactories, exportedFactories, findFactory) + }, [exports, malls, baseFactories, findFactory, exportedFactories]) const [suggestionsExport, suggestionMall] = useMemo<[EnrichedEntity[], EnrichedEntity[]]>(() => { const selectedValues = uniquify([...exports, ...malls]) @@ -58,110 +48,142 @@ const GroupBoxBase: FC = ({ group }) => { const prerequisites = Object.keys(factory.recipe.prerequisites ?? {}) return prerequisites.every(pre => availableIngredients.includes(pre)) }) - .reduce((acc, factory) => - (factory.usedBy?.length ?? 0) >= 3 - ? [[...acc[0], factory], acc[1]] - : [acc[0], [...acc[1], factory]], + .reduce( + (acc, factory) => + (factory.usedBy?.length ?? 0) >= 3 + ? [[...acc[0], factory], acc[1]] + : [acc[0], [...acc[1], factory]], [[], []] as [EnrichedEntity[], EnrichedEntity[]] ) }, [exports, malls, intermediates, inputs, factories, doNotSuggest]) - const addFactory = useCallback((uid: string, type: Parameters[2]) => { - setFactories(name, [...group[type], uid], type) - }, [group, name, setFactories]) + const addFactory = useCallback( + (uid: string, type: Parameters[2]) => { + setFactories(name, [...group[type], uid], type) + }, + [group, name, setFactories] + ) - const setExportFactories = useCallback((factories: string[]) => setFactories(name, factories, 'exports'), [setFactories, name]) - const setMallFactories = useCallback((factories: string[]) => setFactories(name, factories, 'malls'), [setFactories, name]) + const setExportFactories = useCallback( + (exportFactories: string[]) => setFactories(name, exportFactories, 'exports'), + [setFactories, name] + ) + const setMallFactories = useCallback( + (mallFactories: string[]) => setFactories(name, mallFactories, 'malls'), + [setFactories, name] + ) - return
-

{ - event.currentTarget.innerText = event.currentTarget.innerText.trim() - renameGroup(name, event.currentTarget.innerText); - }} - > - {name} -

- 👁 - -

Exported Factories

- -

Mall Factories

- - { inputs.length ? <> -

Input Factories ({inputs.length})

-
- { inputs.map(input => { - event.preventDefault() - setIgnoredFactories([...ignoredFactories, input]) - }} - rightClickText={"Exclude this recipe from suggestions"} - />) } -
- : null } - { intermediates.length ? <> -

Intermediate Factories ({intermediates.length})

-
- { intermediates.map(intermediate => ) } -
- : null } - { suggestionsExport.length ? <> -

Suggestions (Export)

-
- { suggestionsExport.map(suggestion => addFactory(suggestion.href, 'exports')} - onContextMenu={event => { - event.preventDefault() - setIgnoredFactories([...ignoredFactories, suggestion.href]) - }} - leftClickText={"Add to exported factories"} - rightClickText={"Exclude this recipe from suggestions"} - />) } -
- : null } - { suggestionMall.length ? <> -

Suggestions (Mall)

-
- { suggestionMall.map(suggestion => addFactory(suggestion.href, 'malls')} - onContextMenu={event => { - event.preventDefault() - setIgnoredFactories([...ignoredFactories, suggestion.href]) - }} - leftClickText={"Add to mall factories"} - rightClickText={"Exclude this recipe from suggestions"} - />) } -
- : null } -
+ return ( +
+

{ + event.currentTarget.innerText = event.currentTarget.innerText.trim() + renameGroup(name, event.currentTarget.innerText) + }} + > + {name} +

+ + 👁 + + +

Exported Factories

+ +

Mall Factories

+ + {inputs.length ? ( + <> +

Input Factories ({inputs.length})

+
+ {inputs.map(input => ( + { + event.preventDefault() + setIgnoredFactories([...ignoredFactories, input]) + }} + rightClickText={'Exclude this recipe from suggestions'} + /> + ))} +
+ + ) : null} + {intermediates.length ? ( + <> +

Intermediate Factories ({intermediates.length})

+
+ {intermediates.map(intermediate => ( + + ))} +
+ + ) : null} + {suggestionsExport.length ? ( + <> +

Suggestions (Export)

+
+ {suggestionsExport.map(suggestion => ( + addFactory(suggestion.href, 'exports')} + onContextMenu={event => { + event.preventDefault() + setIgnoredFactories([...ignoredFactories, suggestion.href]) + }} + leftClickText={'Add to exported factories'} + rightClickText={'Exclude this recipe from suggestions'} + /> + ))} +
+ + ) : null} + {suggestionMall.length ? ( + <> +

Suggestions (Mall)

+
+ {suggestionMall.map(suggestion => ( + addFactory(suggestion.href, 'malls')} + onContextMenu={event => { + event.preventDefault() + setIgnoredFactories([...ignoredFactories, suggestion.href]) + }} + leftClickText={'Add to mall factories'} + rightClickText={'Exclude this recipe from suggestions'} + /> + ))} +
+ + ) : null} +
+ ) } export const GroupBox = memo(GroupBoxBase) diff --git a/components/home/Home.tsx b/components/home/Home.tsx index d460f5d..cfcf15a 100644 --- a/components/home/Home.tsx +++ b/components/home/Home.tsx @@ -1,18 +1,18 @@ -import {FC, useMemo, useRef, useState} from "react"; -import {GroupBox} from "./GroupBox/GroupBox"; -import styles from "./Home.module.css" -import {useFactories} from "../../src/hooks/useFactories"; -import {EnrichedEntity} from "../../src/types"; -import {EntitySpan} from "./EntitySpan/EntitySpan"; -import {useGroups} from "../contexts/GroupProvider"; -import {Preferences} from "./Preferences/Preferences"; -import {download, streamToArrayBuffer} from "../../src/download"; -import Link from "next/link"; -import {useRouter} from "next/router"; +import { FC, useMemo, useRef, useState } from 'react' +import { GroupBox } from './GroupBox/GroupBox' +import styles from './Home.module.css' +import { useFactories } from '../../src/hooks/useFactories' +import { EnrichedEntity } from '../../src/types' +import { EntitySpan } from './EntitySpan/EntitySpan' +import { useGroups } from '../contexts/GroupProvider' +import { Preferences } from './Preferences/Preferences' +import { download, streamToArrayBuffer } from '../../src/download' +import Link from 'next/link' +import { useRouter } from 'next/router' export const Home: FC = () => { const router = useRouter() - const {factories} = useFactories() + const { factories } = useFactories() const { groups, addGroup, @@ -23,13 +23,14 @@ export const Home: FC = () => { store, load } = useGroups() - const [newGroupValue, setNewGroupValue] = useState("New group") + const [newGroupValue, setNewGroupValue] = useState('New group') const inputRef = useRef(null) const [missingExport, missingMall] = useMemo<[EnrichedEntity[], EnrichedEntity[]]>(() => { return factories .filter(factory => !doNotSuggest.has(factory.href) && factory.recipe) - .reduce((acc, factory) => + .reduce( + (acc, factory) => (factory.usedBy?.length ?? 0) >= 3 ? [[...acc[0], factory], acc[1]] : [acc[0], [...acc[1], factory]], @@ -40,49 +41,66 @@ export const Home: FC = () => { return (

Factorio Microservices

- - - { - const stream = evt.currentTarget.files?.[0].stream() as globalThis.ReadableStream|undefined - if (stream) { - const array = await streamToArrayBuffer(stream) - load(array) - if (inputRef.current) inputRef.current.value = null as unknown as string - } - }}/> - Visualize + + + { + const stream = evt.currentTarget.files?.[0].stream() as + | globalThis.ReadableStream + | undefined + if (stream) { + const array = await streamToArrayBuffer(stream) + load(array) + if (inputRef.current) inputRef.current.value = null as unknown as string + } + }} + /> + Visualize
Missing export factories
- { missingExport.map(missing => ( + {missingExport.map(missing => ( { - addGroup(newGroupValue !== "New group" ? newGroupValue : missing.name, [missing.href]) - setNewGroupValue("New group") + addGroup(newGroupValue !== 'New group' ? newGroupValue : missing.name, [ + missing.href + ]) + setNewGroupValue('New group') }} onContextMenu={event => { event.preventDefault() setIgnoredFactories([...ignoredFactories, missing.href]) }} - leftClickText={"Create a new group with this name and item as exported factory"} - rightClickText={"Exclude this recipe from suggestions"} + leftClickText={'Create a new group with this name and item as exported factory'} + rightClickText={'Exclude this recipe from suggestions'} /> ))}
@@ -90,31 +108,34 @@ export const Home: FC = () => {
Missing mall factories
- { missingMall.map(missing => ( + {missingMall.map(missing => ( { - addGroup(newGroupValue !== "New group" ? newGroupValue : missing.name, [], [missing.href]) - setNewGroupValue("New group") + addGroup( + newGroupValue !== 'New group' ? newGroupValue : missing.name, + [], + [missing.href] + ) + setNewGroupValue('New group') }} onContextMenu={event => { event.preventDefault() setIgnoredFactories([...ignoredFactories, missing.href]) }} - leftClickText={"Create a new group with this name and item as mall factory"} - rightClickText={"Exclude this recipe from suggestions"} + leftClickText={'Create a new group with this name and item as mall factory'} + rightClickText={'Exclude this recipe from suggestions'} /> ))}
- { - Object - .values(groups) - .sort((a, b) => a.name.localeCompare(b.name)) - .map((group) => ) - } + {Object.values(groups) + .sort((a, b) => a.name.localeCompare(b.name)) + .map(group => ( + + ))}
) diff --git a/components/home/LeftClickIcon/LeftClickIcon.tsx b/components/home/LeftClickIcon/LeftClickIcon.tsx index 7b9cf28..7639222 100644 --- a/components/home/LeftClickIcon/LeftClickIcon.tsx +++ b/components/home/LeftClickIcon/LeftClickIcon.tsx @@ -1,4 +1,4 @@ -import {FC} from "react"; +import { FC } from 'react' interface Props { className?: string @@ -6,11 +6,25 @@ interface Props { classClick?: string } -export const LeftClickIcon: FC = ({className, classBody, classClick}) => { +export const LeftClickIcon: FC = ({ className, classBody, classClick }) => { return ( - - - + + + ) } diff --git a/components/home/Preferences/Preferences.tsx b/components/home/Preferences/Preferences.tsx index 4a8cdfe..22551f3 100644 --- a/components/home/Preferences/Preferences.tsx +++ b/components/home/Preferences/Preferences.tsx @@ -1,42 +1,42 @@ -import {FC, useState} from "react"; -import {FactorySelect} from "../FactorySelect/FactorySelect"; -import {useGroups} from "../../contexts/GroupProvider"; +import { FC, useState } from 'react' +import { FactorySelect } from '../FactorySelect/FactorySelect' +import { useGroups } from '../../contexts/GroupProvider' export const Preferences: FC = () => { - const { - addGroup, - baseFactories, - setBaseFactories, - ignoredFactories, - setIgnoredFactories - } = useGroups() - const [newGroupValue, setNewGroupValue] = useState("New group") - return <> -
- Basic Values - -
-
- Ignored Values - -
-
- Add new groups -
- + const { addGroup, baseFactories, setBaseFactories, ignoredFactories, setIgnoredFactories } = + useGroups() + const [newGroupValue, setNewGroupValue] = useState('New group') + return ( + <> +
+ Basic Values + +
+
+ Ignored Values + +
+
+ Add new groups +
+ + ) } diff --git a/components/home/Recipe/Recipe.tsx b/components/home/Recipe/Recipe.tsx index 120ed91..a834e52 100644 --- a/components/home/Recipe/Recipe.tsx +++ b/components/home/Recipe/Recipe.tsx @@ -1,24 +1,29 @@ -import {FC} from "react" -import {Recipe} from "../../../src/types" -import {EntityIcon} from "../EntityIcon/EntityIcon"; +import { FC } from 'react' +import { Recipe } from '../../../src/types' +import { EntityIcon } from '../EntityIcon/EntityIcon' import styles from './Recipe.module.css' interface Props { recipe: Recipe } -export const RecipeSpan: FC = ({recipe}) => { - const toEntityIcon = ([key, amount]: [string, number]) => - const joinByPlus = (elems: JSX.Element[]) => elems.reduce((acc, curr) => { - if (acc.length) { - return [...acc, '+', curr] - } else { - return [curr] - } - }, [] as (JSX.Element|string)[]) - const before = Object.entries({...recipe.prerequisites}).map(toEntityIcon) - const after = Object.entries({...recipe.output}).map(toEntityIcon) - return
- {joinByPlus([toEntityIcon(['/Time', recipe.time]), ...before])} → {joinByPlus(after)} - +export const RecipeSpan: FC = ({ recipe }) => { + const toEntityIcon = ([key, amount]: [string, number]) => ( + + ) + const joinByPlus = (elems: JSX.Element[]) => + elems.reduce((acc, curr) => { + if (acc.length) { + return [...acc, '+', curr] + } else { + return [curr] + } + }, [] as (JSX.Element | string)[]) + const before = Object.entries({ ...recipe.prerequisites }).map(toEntityIcon) + const after = Object.entries({ ...recipe.output }).map(toEntityIcon) + return ( + + {joinByPlus([toEntityIcon(['/Time', recipe.time]), ...before])} → {joinByPlus(after)} + + ) } diff --git a/components/shared/ProducingGraph/ProducingGraph.module.css b/components/shared/ProducingGraph/ProducingGraph.module.css index e70591f..d393e8e 100644 --- a/components/shared/ProducingGraph/ProducingGraph.module.css +++ b/components/shared/ProducingGraph/ProducingGraph.module.css @@ -17,8 +17,8 @@ .node { padding: 0.5em; border-radius: 4px; - border: 1px solid #DDDDDD; - background-color: #EEE; + border: 1px solid #dddddd; + background-color: #eee; } .hidden { diff --git a/components/shared/ProducingGraph/ProducingGraph.tsx b/components/shared/ProducingGraph/ProducingGraph.tsx index 762c10e..cb493b8 100644 --- a/components/shared/ProducingGraph/ProducingGraph.tsx +++ b/components/shared/ProducingGraph/ProducingGraph.tsx @@ -1,29 +1,44 @@ -import {FC, HTMLProps, PropsWithChildren, useEffect, useRef, useState} from "react"; +import { FC, HTMLProps, PropsWithChildren, useEffect, useRef, useState } from 'react' import styles from './ProducingGraph.module.css' -import {EntityIcon} from "../../home/EntityIcon/EntityIcon"; -import {createPath, drawLine} from "../../../src/svg"; -import {AdditionalNode, GraphNode, GraphNodeWithIds, isAdditionalNode} from "../../../src/graph-untangle/types"; -import {graphUntangled} from "../../../src/graph-untangle"; -import {Dict} from "../../../src/types"; +import { EntityIcon } from '../../home/EntityIcon/EntityIcon' +import { createPath, drawLine } from '../../../src/svg' +import { + AdditionalNode, + GraphNode, + GraphNodeWithIds, + isAdditionalNode +} from '../../../src/graph-untangle/types' +import { graphUntangled } from '../../../src/graph-untangle' +import { Dict } from '../../../src/types' -interface Props { +interface Props> { nodes: GraphNode[] inputs: string[] outputs?: string[] - childType: FC & {node: GraphNode}> + childType: FC & { node: GraphNode }> } -export const ProducingGraph = ,>({nodes, inputs, outputs, childType: ChildType}: PropsWithChildren>) => { +export const ProducingGraph = >({ + nodes, + inputs, + outputs, + childType: ChildType +}: PropsWithChildren>) => { const planeRef = useRef(null) - const [[rows, nodeMap], setGraph] = useState<[string[][], Dict>]>(graphUntangled(nodes, inputs, outputs ?? [], 3000)) + const [[rows, nodeMap]] = useState<[string[][], Dict>]>( + graphUntangled(nodes, inputs, outputs ?? [], 3000) + ) useEffect(() => { if (!planeRef.current) return const plane = planeRef.current function createSvgElement() { - const elem = document.createElementNS("http://www.w3.org/2000/svg", "svg") + const elem = document.createElementNS('http://www.w3.org/2000/svg', 'svg') elem.id = 'arrows' - elem.setAttribute('style', 'position: absolute; inset: 0 0 0 0; pointer-events: none; z-index: -10;') + elem.setAttribute( + 'style', + 'position: absolute; inset: 0 0 0 0; pointer-events: none; z-index: -10;' + ) elem.setAttributeNS(null, 'stroke', 'black') elem.setAttributeNS(null, 'fill', 'none') plane.appendChild(elem) @@ -37,69 +52,75 @@ export const ProducingGraph = ,>({nodes, inputs, outputs svg.setAttributeNS(null, 'viewBox', `0 0 ${width} ${height}`) svg.replaceChildren() - let paths: string[] = [] + const paths: string[] = [] plane.querySelectorAll('[data-outputs]').forEach(startNode => { if (!(startNode instanceof HTMLElement)) return - (startNode.dataset.outputs?.split(' ') ?? []).forEach(output => { + ;(startNode.dataset.outputs?.split(' ') ?? []).forEach(output => { const endNode = plane.querySelector(`[data-name="${output}"]`) if (!(endNode instanceof HTMLElement)) return - paths.push(createPath(plane.getBoundingClientRect(), startNode.getBoundingClientRect(), endNode.getBoundingClientRect())) + paths.push( + createPath( + plane.getBoundingClientRect(), + startNode.getBoundingClientRect(), + endNode.getBoundingClientRect() + ) + ) }) }) plane.querySelectorAll('[data-hidden="true"][data-outputs]').forEach(elem => { if (!(elem instanceof HTMLElement)) return paths.push(drawLine(plane.getBoundingClientRect(), elem.getBoundingClientRect())) }) - const path = document.createElementNS('http://www.w3.org/2000/svg',"path") + const path = document.createElementNS('http://www.w3.org/2000/svg', 'path') path.setAttributeNS(null, 'd', paths.join(' ')) svg.appendChild(path) }) - return
- {rows.map((row, colIdx) => ( -
- { - row.map((uid) => { + return ( +
+ {rows.map((row, colIdx) => ( +
+ {row.map(uid => { const node = nodeMap[uid] - return ( - !isAdditionalNode(node) - ? 0}> - - - : node.___type === 'h' - ? - : node.___type === 'i' - ? - - - : - ); - }) - } -
- ))} -
+ return !isAdditionalNode(node) ? ( + 0} + > + + + ) : node.___type === 'h' ? ( + + ) : node.___type === 'i' ? ( + + + + ) : ( + + ) + })} +
+ ))} +
+ ) } diff --git a/components/shared/ScrollContainer/ScrollContainer.tsx b/components/shared/ScrollContainer/ScrollContainer.tsx index 063a02e..fc2a180 100644 --- a/components/shared/ScrollContainer/ScrollContainer.tsx +++ b/components/shared/ScrollContainer/ScrollContainer.tsx @@ -1,25 +1,25 @@ -import {FC, PropsWithChildren, useEffect, useRef} from "react"; -import IndianaDragScoll from "react-indiana-drag-scroll"; +import { FC, PropsWithChildren, useEffect, useRef } from 'react' +import IndianaDragScoll from 'react-indiana-drag-scroll' import styles from './ScrollContainer.module.css' -export const ScrollContainer: FC = ({children}) => { - const container = useRef(null); +export const ScrollContainer: FC = ({ children }) => { + const container = useRef(null) useEffect(() => { if (container.current) { container.current.oncontextmenu = e => e.preventDefault() } - }, []); + }, []) - return -
- {children} -
-
+ return ( + +
{children}
+
+ ) } diff --git a/components/visualize/NodeDetails/NodeDetails.tsx b/components/visualize/NodeDetails/NodeDetails.tsx index 2cf4922..aa55acd 100644 --- a/components/visualize/NodeDetails/NodeDetails.tsx +++ b/components/visualize/NodeDetails/NodeDetails.tsx @@ -1,9 +1,9 @@ -import {FC, HTMLProps} from "react"; -import {GraphNode} from "../../shared/ProducingGraph/ProducingGraph"; -import {Recipe} from "../../../src/types"; -import cx from "classnames"; -import styles from "./NodeDetails.module.css"; -import {RecipeSpan} from "../../home/Recipe/Recipe"; +import { FC, HTMLProps } from 'react' +import { Recipe } from '../../../src/types' +import cx from 'classnames' +import styles from './NodeDetails.module.css' +import { RecipeSpan } from '../../home/Recipe/Recipe' +import { GraphNode } from '../../../src/graph-untangle/types' export type DetailGraphNode = GraphNode<{ recipes: Recipe[] @@ -13,9 +13,13 @@ interface Props extends HTMLProps { node: DetailGraphNode } -export const NodeDetails: FC = ({node, className, ...props}) => { - return
-

{node.name}

- {node.recipes.map((recipe, idx) => )} -
+export const NodeDetails: FC = ({ node, className, ...props }) => { + return ( +
+

{node.name}

+ {node.recipes.map((recipe, idx) => ( + + ))} +
+ ) } diff --git a/components/visualize/NodeOverview/NodeOverview.module.css b/components/visualize/NodeOverview/NodeOverview.module.css index ad1f1ab..047ab20 100644 --- a/components/visualize/NodeOverview/NodeOverview.module.css +++ b/components/visualize/NodeOverview/NodeOverview.module.css @@ -4,9 +4,9 @@ } .tiny { - font-size: 0.5em; - margin-top: -1.6em; - } + font-size: 0.5em; + margin-top: -1.6em; +} .small { font-size: 0.8em; @@ -15,4 +15,3 @@ .linkOut { margin-inline-end: 0.5em; } - diff --git a/components/visualize/NodeOverview/NodeOverview.tsx b/components/visualize/NodeOverview/NodeOverview.tsx index c408ece..a7ec886 100644 --- a/components/visualize/NodeOverview/NodeOverview.tsx +++ b/components/visualize/NodeOverview/NodeOverview.tsx @@ -1,14 +1,13 @@ -import {FC, HTMLProps} from "react"; -import {GraphNode} from "../../shared/ProducingGraph/ProducingGraph"; -import {EnrichedEntity, Recipe} from "../../../src/types"; -import cx from "classnames"; -import styles from "./NodeOverview.module.css"; -import {RecipeSpan} from "../../home/Recipe/Recipe"; -import Link from "next/link"; -import {EntityIcon} from "../../home/EntityIcon/EntityIcon"; +import { FC, HTMLProps } from 'react' +import { EnrichedEntity } from '../../../src/types' +import cx from 'classnames' +import styles from './NodeOverview.module.css' +import Link from 'next/link' +import { EntityIcon } from '../../home/EntityIcon/EntityIcon' +import { GraphNode } from '../../../src/graph-untangle/types' export type OverviewGraphNode = GraphNode<{ - icons: (EnrichedEntity|string)[] + icons: (EnrichedEntity | string)[] linkOut: string }> @@ -16,21 +15,38 @@ interface Props extends HTMLProps { node: OverviewGraphNode } -export const NodeOverview: FC = ({node, className, ...props}) => { - return
-

🔗{node.name}

- { node.icons?.length ?
- {node.icons.map((input) => )} -
: null } -

Inputs

-
- {node.inputs.map((input) => )} -
- {node.outputs.length ? <> -

Outputs

+export const NodeOverview: FC = ({ node, className, ...props }) => { + return ( +
+

+ + 🔗 + + {node.name} +

+ {node.icons?.length ? ( +
+ {node.icons.map(input => ( + + ))} +
+ ) : null} +

Inputs

- {node.outputs.map((input) => )} + {node.inputs.map(input => ( + + ))}
- : null} -
+ {node.outputs.length ? ( + <> +

Outputs

+
+ {node.outputs.map(input => ( + + ))} +
+ + ) : null} +
+ ) } diff --git a/components/visualize/PageDetails.tsx b/components/visualize/PageDetails.tsx index 96d8ec8..2c58e09 100644 --- a/components/visualize/PageDetails.tsx +++ b/components/visualize/PageDetails.tsx @@ -1,72 +1,74 @@ -import {useRouter} from "next/router"; -import {GroupProvider, useGroups} from "../contexts/GroupProvider"; -import {useFactories} from "../../src/hooks/useFactories"; -import {FC, useEffect, useMemo} from "react"; -import {calculateInputs} from "../../src/calculateInputs"; -import {DetailGraphNode, NodeDetails} from "./NodeDetails/NodeDetails"; -import {groupBy, isNonNullable, uniquify} from "../../src/utils"; -import {EnrichedEntity} from "../../src/types"; -import Head from "next/head"; -import {ScrollContainer} from "../shared/ScrollContainer/ScrollContainer"; -import {ProducingGraph} from "../shared/ProducingGraph/ProducingGraph"; +import { useRouter } from 'next/router' +import { useGroups } from '../contexts/GroupProvider' +import { useFactories } from '../../src/hooks/useFactories' +import { FC, useEffect, useMemo } from 'react' +import { calculateInputs } from '../../src/calculateInputs' +import { DetailGraphNode, NodeDetails } from './NodeDetails/NodeDetails' +import { groupBy, isNonNullable, uniquify } from '../../src/utils' +import { EnrichedEntity } from '../../src/types' +import Head from 'next/head' +import { ScrollContainer } from '../shared/ScrollContainer/ScrollContainer' +import { ProducingGraph } from '../shared/ProducingGraph/ProducingGraph' export const PageDetails: FC = () => { - const {query: {name}} = useRouter() const { - exportedFactories, - baseFactories, - ignoredFactories, - groups - } = useGroups() - const { - findFactory - } = useFactories() + query: { name } + } = useRouter() + const { exportedFactories, baseFactories, groups } = useGroups() + const { findFactory } = useFactories() useEffect(() => { - document.body.classList.add("scroll"); - return () => document.body.classList.remove("scroll") - }, []); + document.body.classList.add('scroll') + return () => document.body.classList.remove('scroll') + }, []) const group = typeof name === 'string' ? groups[name] : undefined - const [inputFactories, intermediateFactories] = useMemo>(() => { + const [inputFactories, intermediateFactories] = useMemo< + ReturnType + >(() => { if (!group) return [[], []] return calculateInputs( [...group.exports, ...group.malls], - ignoredFactories, baseFactories, exportedFactories, findFactory ) - }, [baseFactories, exportedFactories, findFactory, group, ignoredFactories]) + }, [baseFactories, exportedFactories, findFactory, group]) const producingNodes: DetailGraphNode[] = useMemo(() => { if (!group) return [] const nodes = uniquify([...intermediateFactories, ...group.exports, ...group.malls]) .map(findFactory) .filter(isNonNullable) - .map((factory: EnrichedEntity) => ({ - inputs: Object.keys(factory.recipe?.prerequisites ?? {}).sort((a, b) => a.localeCompare(b)), - outputs: Object.keys(factory.recipe?.output ?? {}).sort((a, b) => a.localeCompare(b)), - name: factory.name, - recipes: [factory.recipe] - } as DetailGraphNode)) - return Object - .values(groupBy(nodes, node => node.inputs.join())) - .map(nodesOfInput => ({ - inputs: nodesOfInput[0].inputs, - outputs: uniquify(nodesOfInput.flatMap(node => node.outputs)), - name: nodesOfInput.map(node => node.name).join(', '), - recipes: nodesOfInput.flatMap(node => node.recipes) - } as DetailGraphNode)) + .map( + (factory: EnrichedEntity) => + ({ + inputs: Object.keys(factory.recipe?.prerequisites ?? {}).sort((a, b) => + a.localeCompare(b) + ), + outputs: Object.keys(factory.recipe?.output ?? {}).sort((a, b) => a.localeCompare(b)), + name: factory.name, + recipes: [factory.recipe] + } as DetailGraphNode) + ) + return Object.values(groupBy(nodes, node => node.inputs.join())).map( + nodesOfInput => + ({ + inputs: nodesOfInput[0].inputs, + outputs: uniquify(nodesOfInput.flatMap(node => node.outputs)), + name: nodesOfInput.map(node => node.name).join(', '), + recipes: nodesOfInput.flatMap(node => node.recipes) + } as DetailGraphNode) + ) }, [findFactory, group, intermediateFactories]) return ( <> Factorio Microservices - - + +
diff --git a/package.json b/package.json index 6c3c707..e579776 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,11 @@ "dev": "next dev", "build": "next build", "start": "next start", - "lint": "next lint" + "lint": "next lint", + "lint:fix": "tsc --noEmit && prettier --write --loglevel warn . && eslint --fix . && stylelint --fix **/*.css", + "eslint:fix": "eslint --fix .", + "stylelint:fix": " stylelint --fix **/*.css", + "prepare": "husky install" }, "dependencies": { "classnames": "^2.3.1", @@ -30,9 +34,18 @@ "@types/react": "18.0.17", "@types/react-dom": "18.0.6", "@types/seedrandom": "^3.0.2", + "@typescript-eslint/eslint-plugin": "^5.33.1", + "@typescript-eslint/parser": "^5.33.1", "eslint": "8.21.0", "eslint-config-next": "12.2.4", + "eslint-plugin-unused-imports": "^2.0.0", + "husky": "^8.0.1", "json-schema-to-typescript": "^11.0.2", + "lint-staged": "^13.0.3", + "prettier": "^2.7.1", + "stylelint": "^14.10.0", + "stylelint-config-idiomatic-order": "^8.1.0", + "stylelint-config-standard": "^27.0.0", "typescript": "4.7.4" } } diff --git a/pages/_app.tsx b/pages/_app.tsx index f322696..30d8431 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -1,7 +1,6 @@ import '../styles/globals.css' import type { AppProps } from 'next/app' -import {GroupProvider} from "../components/contexts/GroupProvider"; -import {FC} from "react"; +import { FC } from 'react' const MyApp: FC = ({ Component, pageProps }) => { return diff --git a/pages/_document.tsx b/pages/_document.tsx index f52fbcb..cae57e5 100644 --- a/pages/_document.tsx +++ b/pages/_document.tsx @@ -1,18 +1,18 @@ -import {Html, Main, NextScript, DocumentProps, Head} from 'next/document'; -import {FC} from "react"; -import Dict = NodeJS.Dict; +import { Html, Main, NextScript, DocumentProps, Head } from 'next/document' +import { FC } from 'react' +import Dict = NodeJS.Dict const MyDocument: FC = ({ __NEXT_DATA__ }) => { - const pageProps: Dict|undefined = __NEXT_DATA__?.props?.pageProps; + const pageProps: Dict | undefined = __NEXT_DATA__?.props?.pageProps return ( -
- +
+ - ); + ) } export default MyDocument diff --git a/pages/api/[id]/factories.ts b/pages/api/[id]/factories.ts index 605af86..16329be 100644 --- a/pages/api/[id]/factories.ts +++ b/pages/api/[id]/factories.ts @@ -1,8 +1,8 @@ -import {nextHandler} from "../../../src/utils/errors"; -import {validate} from "../../../src/validation"; -import {IdParam, SetFactoryArrayBody} from "../../../src/types/ApiSchemas"; -import {setFactories} from "../../../src/database/groups"; -import {waitForInitSchemas} from "../../../src/validation/schemas"; +import { nextHandler } from '../../../src/utils/errors' +import { validate } from '../../../src/validation' +import { IdParam, SetFactoryArrayBody } from '../../../src/types/ApiSchemas' +import { setFactories } from '../../../src/database/groups' +import { waitForInitSchemas } from '../../../src/validation/schemas' const handler = nextHandler(async (req, res) => { if (req.method !== 'POST') throw new Error('Invalid method') diff --git a/pages/api/[id]/group/[name]/add.ts b/pages/api/[id]/group/[name]/add.ts index 748f2f0..fb3e814 100644 --- a/pages/api/[id]/group/[name]/add.ts +++ b/pages/api/[id]/group/[name]/add.ts @@ -1,8 +1,8 @@ -import {nextHandler} from "../../../../../src/utils/errors"; -import {validate} from "../../../../../src/validation"; -import {GroupIdParam} from "../../../../../src/types/ApiSchemas"; -import {addGroup} from "../../../../../src/database/groups"; -import {waitForInitSchemas} from "../../../../../src/validation/schemas"; +import { nextHandler } from '../../../../../src/utils/errors' +import { validate } from '../../../../../src/validation' +import { GroupIdParam } from '../../../../../src/types/ApiSchemas' +import { addGroup } from '../../../../../src/database/groups' +import { waitForInitSchemas } from '../../../../../src/validation/schemas' const handler = nextHandler(async (req, res) => { if (req.method !== 'POST') throw new Error('Invalid method') diff --git a/pages/api/[id]/group/[name]/factories.ts b/pages/api/[id]/group/[name]/factories.ts index d2d0fdf..b500cd1 100644 --- a/pages/api/[id]/group/[name]/factories.ts +++ b/pages/api/[id]/group/[name]/factories.ts @@ -1,14 +1,17 @@ -import {nextHandler} from "../../../../../src/utils/errors"; -import {validate} from "../../../../../src/validation"; -import {GroupIdParam, GroupSetFactoryArrayBody} from "../../../../../src/types/ApiSchemas"; -import {setFactoriesOfGroup} from "../../../../../src/database/groups"; -import {waitForInitSchemas} from "../../../../../src/validation/schemas"; +import { nextHandler } from '../../../../../src/utils/errors' +import { validate } from '../../../../../src/validation' +import { GroupIdParam, GroupSetFactoryArrayBody } from '../../../../../src/types/ApiSchemas' +import { setFactoriesOfGroup } from '../../../../../src/database/groups' +import { waitForInitSchemas } from '../../../../../src/validation/schemas' const handler = nextHandler(async (req, res) => { if (req.method !== 'POST') throw new Error('Invalid method') await waitForInitSchemas.resolve() const { transformed: params } = validate(req.query, '/GroupIdParam') - const { transformed: body } = validate(req.body, '/GroupSetFactoryArrayBody') + const { transformed: body } = validate( + req.body, + '/GroupSetFactoryArrayBody' + ) const success = await setFactoriesOfGroup(params.id, params.name, body.type, body.factories) res.json({ success }) diff --git a/pages/api/[id]/group/[name]/remove.ts b/pages/api/[id]/group/[name]/remove.ts index b8c0798..8ac6770 100644 --- a/pages/api/[id]/group/[name]/remove.ts +++ b/pages/api/[id]/group/[name]/remove.ts @@ -1,8 +1,8 @@ -import {nextHandler} from "../../../../../src/utils/errors"; -import {validate} from "../../../../../src/validation"; -import {GroupIdParam} from "../../../../../src/types/ApiSchemas"; -import {removeGroup} from "../../../../../src/database/groups"; -import {waitForInitSchemas} from "../../../../../src/validation/schemas"; +import { nextHandler } from '../../../../../src/utils/errors' +import { validate } from '../../../../../src/validation' +import { GroupIdParam } from '../../../../../src/types/ApiSchemas' +import { removeGroup } from '../../../../../src/database/groups' +import { waitForInitSchemas } from '../../../../../src/validation/schemas' const handler = nextHandler(async (req, res) => { if (req.method !== 'POST') throw new Error('Invalid method') diff --git a/pages/api/[id]/group/[name]/rename.ts b/pages/api/[id]/group/[name]/rename.ts index 9c49710..8ab2a0e 100644 --- a/pages/api/[id]/group/[name]/rename.ts +++ b/pages/api/[id]/group/[name]/rename.ts @@ -1,8 +1,8 @@ -import {nextHandler} from "../../../../../src/utils/errors"; -import {validate} from "../../../../../src/validation"; -import {GroupIdParam, GroupRenameBody} from "../../../../../src/types/ApiSchemas"; -import {renameGroup} from "../../../../../src/database/groups"; -import {waitForInitSchemas} from "../../../../../src/validation/schemas"; +import { nextHandler } from '../../../../../src/utils/errors' +import { validate } from '../../../../../src/validation' +import { GroupIdParam, GroupRenameBody } from '../../../../../src/types/ApiSchemas' +import { renameGroup } from '../../../../../src/database/groups' +import { waitForInitSchemas } from '../../../../../src/validation/schemas' const handler = nextHandler(async (req, res) => { if (req.method !== 'POST') throw new Error('Invalid method') diff --git a/pages/api/dev/schemas.ts b/pages/api/dev/schemas.ts index 4d6cbf3..e28ade5 100644 --- a/pages/api/dev/schemas.ts +++ b/pages/api/dev/schemas.ts @@ -1,9 +1,10 @@ -import {GroupData, setGroups} from "../../../src/database/groups"; -import {NetworkError, nextHandler} from "../../../src/utils/errors"; -import getConfig from "next/config"; -import {addSchemas, waitForInitSchemas} from "../../../src/validation/schemas"; +import { NetworkError, nextHandler } from '../../../src/utils/errors' +import getConfig from 'next/config' +import { waitForInitSchemas } from '../../../src/validation/schemas' -const {publicRuntimeConfig: {TENANT_TYPE}} = getConfig() +const { + publicRuntimeConfig: { TENANT_TYPE } +} = getConfig() const handler = nextHandler(async (req, res) => { if (req.method !== 'GET') throw new NetworkError('Invalid method') diff --git a/pages/api/submit.ts b/pages/api/submit.ts index 3df5940..c26db4f 100644 --- a/pages/api/submit.ts +++ b/pages/api/submit.ts @@ -1,6 +1,6 @@ -import {GroupData, setGroups} from "../../src/database/groups"; -import {nextHandler} from "../../src/utils/errors"; -import {waitForInitSchemas} from "../../src/validation/schemas"; +import { GroupData, setGroups } from '../../src/database/groups' +import { nextHandler } from '../../src/utils/errors' +import { waitForInitSchemas } from '../../src/validation/schemas' const handler = nextHandler(async (req, res) => { if (req.method !== 'POST') throw new Error('Invalid method') diff --git a/pages/index.tsx b/pages/index.tsx index 81f63a4..caf90d0 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -1,23 +1,18 @@ -import type {GetServerSideProps, NextPage} from 'next' +import type { NextPage } from 'next' import Head from 'next/head' -import {Home} from "../components/home/Home"; -import {useEffect} from "react"; -import {GroupProvider} from "../components/contexts/GroupProvider"; -import {getGroup, setGroups} from "../src/database/groups"; -import {Dict, Group} from "../src/types"; -import {getServerSidePropsGroupProvider, PropsGroupProvider} from "../src/getServerSideProps"; +import { Home } from '../components/home/Home' +import { GroupProvider } from '../components/contexts/GroupProvider' +import { getServerSidePropsGroupProvider, PropsGroupProvider } from '../src/getServerSideProps' - - -const Page: NextPage = ({id, ...initial}) => { +const Page: NextPage = ({ id, ...initial }) => { return ( Factorio Microservices - - + + - + ) } diff --git a/pages/visualize/[name].tsx b/pages/visualize/[name].tsx index 963d156..b755863 100644 --- a/pages/visualize/[name].tsx +++ b/pages/visualize/[name].tsx @@ -1,13 +1,12 @@ import type { NextPage } from 'next' -import {GroupProvider} from "../../components/contexts/GroupProvider"; -import {getServerSidePropsGroupProvider, PropsGroupProvider} from "../../src/getServerSideProps"; -import {PageDetails} from "../../components/visualize/PageDetails"; +import { GroupProvider } from '../../components/contexts/GroupProvider' +import { getServerSidePropsGroupProvider, PropsGroupProvider } from '../../src/getServerSideProps' +import { PageDetails } from '../../components/visualize/PageDetails' - -const Page: NextPage = ({id, ...initial}) => { +const Page: NextPage = ({ id, ...initial }) => { return ( - + ) } diff --git a/pages/visualize/index.tsx b/pages/visualize/index.tsx index 32e51e7..2ce3ef1 100644 --- a/pages/visualize/index.tsx +++ b/pages/visualize/index.tsx @@ -1,36 +1,31 @@ -import type {NextPage} from 'next' +import type { NextPage } from 'next' import Head from 'next/head' -import {GroupProvider, useGroups} from "../../components/contexts/GroupProvider"; -import {useFactories} from "../../src/hooks/useFactories"; -import {ProducingGraph} from "../../components/shared/ProducingGraph/ProducingGraph"; -import {useEffect, useMemo} from "react"; -import {calculateInputs} from "../../src/calculateInputs"; -import {NodeOverview, OverviewGraphNode} from "../../components/visualize/NodeOverview/NodeOverview"; -import {fixedEncodeURIComponent} from "../../src/utils"; -import {ScrollContainer} from "../../components/shared/ScrollContainer/ScrollContainer"; -import {getServerSidePropsGroupProvider, PropsGroupProvider} from "../../src/getServerSideProps"; +import { GroupProvider, useGroups } from '../../components/contexts/GroupProvider' +import { useFactories } from '../../src/hooks/useFactories' +import { ProducingGraph } from '../../components/shared/ProducingGraph/ProducingGraph' +import { useEffect, useMemo } from 'react' +import { calculateInputs } from '../../src/calculateInputs' +import { + NodeOverview, + OverviewGraphNode +} from '../../components/visualize/NodeOverview/NodeOverview' +import { fixedEncodeURIComponent } from '../../src/utils' +import { ScrollContainer } from '../../components/shared/ScrollContainer/ScrollContainer' +import { getServerSidePropsGroupProvider, PropsGroupProvider } from '../../src/getServerSideProps' -const Page: NextPage = ({id, ...initial}) => { - const { - exportedFactories, - ignoredFactories, - baseFactories, - groups - } = useGroups() - const { - findFactory - } = useFactories() +const Page: NextPage = ({ id, ...initial }) => { + const { exportedFactories, baseFactories, groups } = useGroups() + const { findFactory } = useFactories() useEffect(() => { - document.body.classList.add("scroll"); - return () => document.body.classList.remove("scroll") - }, []); + document.body.classList.add('scroll') + return () => document.body.classList.remove('scroll') + }, []) const producingNodes: OverviewGraphNode[] = useMemo(() => { return Object.values(groups).map(group => ({ inputs: calculateInputs( [...group.exports, ...group.malls], - ignoredFactories, baseFactories, exportedFactories, findFactory @@ -40,19 +35,19 @@ const Page: NextPage = ({id, ...initial}) => { icons: [...group.exports, ...group.malls], linkOut: `./visualize/${fixedEncodeURIComponent(group.name)}` })) - }, [baseFactories, exportedFactories, findFactory, groups, ignoredFactories]) + }, [baseFactories, exportedFactories, findFactory, groups]) return ( Factorio Microservices - - + +

Factorio Microservices

- +
diff --git a/res/details.json b/res/details.json index ad6bd5b..e0cd707 100644 --- a/res/details.json +++ b/res/details.json @@ -3072,4 +3072,4 @@ } } } -] \ No newline at end of file +] diff --git a/res/entities.json b/res/entities.json index 3b3d50f..592a921 100644 --- a/res/entities.json +++ b/res/entities.json @@ -1 +1,989 @@ -[{"name":"Wooden chest","href":"/Wooden_chest","image":"/images/thumb/Wooden_chest.png/32px-Wooden_chest.png"},{"name":"Iron chest","href":"/Iron_chest","image":"/images/thumb/Iron_chest.png/32px-Iron_chest.png"},{"name":"Steel chest","href":"/Steel_chest","image":"/images/thumb/Steel_chest.png/32px-Steel_chest.png"},{"name":"Storage tank","href":"/Storage_tank","image":"/images/thumb/Storage_tank.png/32px-Storage_tank.png"},{"name":"Transport belt","href":"/Transport_belt","image":"/images/thumb/Transport_belt.png/32px-Transport_belt.png"},{"name":"Fast transport belt","href":"/Fast_transport_belt","image":"/images/thumb/Fast_transport_belt.png/32px-Fast_transport_belt.png"},{"name":"Express transport belt","href":"/Express_transport_belt","image":"/images/thumb/Express_transport_belt.png/32px-Express_transport_belt.png"},{"name":"Underground belt","href":"/Underground_belt","image":"/images/thumb/Underground_belt.png/32px-Underground_belt.png"},{"name":"Fast underground belt","href":"/Fast_underground_belt","image":"/images/thumb/Fast_underground_belt.png/32px-Fast_underground_belt.png"},{"name":"Express underground belt","href":"/Express_underground_belt","image":"/images/thumb/Express_underground_belt.png/32px-Express_underground_belt.png"},{"name":"Splitter","href":"/Splitter","image":"/images/thumb/Splitter.png/32px-Splitter.png"},{"name":"Fast splitter","href":"/Fast_splitter","image":"/images/thumb/Fast_splitter.png/32px-Fast_splitter.png"},{"name":"Express splitter","href":"/Express_splitter","image":"/images/thumb/Express_splitter.png/32px-Express_splitter.png"},{"name":"Burner inserter","href":"/Burner_inserter","image":"/images/thumb/Burner_inserter.png/32px-Burner_inserter.png"},{"name":"Inserter","href":"/Inserter","image":"/images/thumb/Inserter.png/32px-Inserter.png"},{"name":"Long-handed inserter","href":"/Long-handed_inserter","image":"/images/thumb/Long-handed_inserter.png/32px-Long-handed_inserter.png"},{"name":"Fast inserter","href":"/Fast_inserter","image":"/images/thumb/Fast_inserter.png/32px-Fast_inserter.png"},{"name":"Filter inserter","href":"/Filter_inserter","image":"/images/thumb/Filter_inserter.png/32px-Filter_inserter.png"},{"name":"Stack inserter","href":"/Stack_inserter","image":"/images/thumb/Stack_inserter.png/32px-Stack_inserter.png"},{"name":"Stack filter inserter","href":"/Stack_filter_inserter","image":"/images/thumb/Stack_filter_inserter.png/32px-Stack_filter_inserter.png"},{"name":"Small electric pole","href":"/Small_electric_pole","image":"/images/thumb/Small_electric_pole.png/32px-Small_electric_pole.png"},{"name":"Medium electric pole","href":"/Medium_electric_pole","image":"/images/thumb/Medium_electric_pole.png/32px-Medium_electric_pole.png"},{"name":"Big electric pole","href":"/Big_electric_pole","image":"/images/thumb/Big_electric_pole.png/32px-Big_electric_pole.png"},{"name":"Substation","href":"/Substation","image":"/images/thumb/Substation.png/32px-Substation.png"},{"name":"Pipe","href":"/Pipe","image":"/images/thumb/Pipe.png/32px-Pipe.png"},{"name":"Pipe to ground","href":"/Pipe_to_ground","image":"/images/thumb/Pipe_to_ground.png/32px-Pipe_to_ground.png"},{"name":"Pump","href":"/Pump","image":"/images/thumb/Pump.png/32px-Pump.png"},{"name":"Rail","href":"/Rail","image":"/images/thumb/Straight_rail.png/32px-Straight_rail.png"},{"name":"Train stop","href":"/Train_stop","image":"/images/thumb/Train_stop.png/32px-Train_stop.png"},{"name":"Rail signal","href":"/Rail_signal","image":"/images/thumb/Rail_signal.png/32px-Rail_signal.png"},{"name":"Rail chain signal","href":"/Rail_chain_signal","image":"/images/thumb/Rail_chain_signal.png/32px-Rail_chain_signal.png"},{"name":"Locomotive","href":"/Locomotive","image":"/images/thumb/Locomotive.png/32px-Locomotive.png"},{"name":"Cargo wagon","href":"/Cargo_wagon","image":"/images/thumb/Cargo_wagon.png/32px-Cargo_wagon.png"},{"name":"Fluid wagon","href":"/Fluid_wagon","image":"/images/thumb/Fluid_wagon.png/32px-Fluid_wagon.png"},{"name":"Artillery wagon","href":"/Artillery_wagon","image":"/images/thumb/Artillery_wagon.png/32px-Artillery_wagon.png"},{"name":"Car","href":"/Car","image":"/images/thumb/Car.png/32px-Car.png"},{"name":"Tank","href":"/Tank","image":"/images/thumb/Tank.png/32px-Tank.png"},{"name":"Spidertron","href":"/Spidertron","image":"/images/thumb/Spidertron.png/32px-Spidertron.png"},{"name":"Spidertron remote","href":"/Spidertron_remote","image":"/images/thumb/Spidertron_remote.png/32px-Spidertron_remote.png"},{"name":"Logistic robot","href":"/Logistic_robot","image":"/images/thumb/Logistic_robot.png/32px-Logistic_robot.png"},{"name":"Construction robot","href":"/Construction_robot","image":"/images/thumb/Construction_robot.png/32px-Construction_robot.png"},{"name":"Active provider chest","href":"/Active_provider_chest","image":"/images/thumb/Active_provider_chest.png/32px-Active_provider_chest.png"},{"name":"Passive provider chest","href":"/Passive_provider_chest","image":"/images/thumb/Passive_provider_chest.png/32px-Passive_provider_chest.png"},{"name":"Storage chest","href":"/Storage_chest","image":"/images/thumb/Storage_chest.png/32px-Storage_chest.png"},{"name":"Buffer chest","href":"/Buffer_chest","image":"/images/thumb/Buffer_chest.png/32px-Buffer_chest.png"},{"name":"Requester chest","href":"/Requester_chest","image":"/images/thumb/Requester_chest.png/32px-Requester_chest.png"},{"name":"Roboport","href":"/Roboport","image":"/images/thumb/Roboport.png/32px-Roboport.png"},{"name":"Lamp","href":"/Lamp","image":"/images/thumb/Lamp.png/32px-Lamp.png"},{"name":"Red wire","href":"/Red_wire","image":"/images/thumb/Red_wire.png/32px-Red_wire.png"},{"name":"Green wire","href":"/Green_wire","image":"/images/thumb/Green_wire.png/32px-Green_wire.png"},{"name":"Arithmetic combinator","href":"/Arithmetic_combinator","image":"/images/thumb/Arithmetic_combinator.png/32px-Arithmetic_combinator.png"},{"name":"Decider combinator","href":"/Decider_combinator","image":"/images/thumb/Decider_combinator.png/32px-Decider_combinator.png"},{"name":"Constant combinator","href":"/Constant_combinator","image":"/images/thumb/Constant_combinator.png/32px-Constant_combinator.png"},{"name":"Power switch","href":"/Power_switch","image":"/images/thumb/Power_switch.png/32px-Power_switch.png"},{"name":"Programmable speaker","href":"/Programmable_speaker","image":"/images/thumb/Programmable_speaker.png/32px-Programmable_speaker.png"},{"name":"Stone brick","href":"/Stone_brick","image":"/images/thumb/Stone_brick.png/32px-Stone_brick.png"},{"name":"Concrete","href":"/Concrete","image":"/images/thumb/Concrete.png/32px-Concrete.png"},{"name":"Hazard concrete","href":"/Hazard_concrete","image":"/images/thumb/Hazard_concrete.png/32px-Hazard_concrete.png"},{"name":"Refined concrete","href":"/Refined_concrete","image":"/images/thumb/Refined_concrete.png/32px-Refined_concrete.png"},{"name":"Refined hazard concrete","href":"/Refined_hazard_concrete","image":"/images/thumb/Refined_hazard_concrete.png/32px-Refined_hazard_concrete.png"},{"name":"Landfill","href":"/Landfill","image":"/images/thumb/Landfill.png/32px-Landfill.png"},{"name":"Cliff explosives","href":"/Cliff_explosives","image":"/images/thumb/Cliff_explosives.png/32px-Cliff_explosives.png"},{"name":"Repair pack","href":"/Repair_pack","image":"/images/thumb/Repair_pack.png/32px-Repair_pack.png"},{"name":"Blueprint","href":"/Blueprint","image":"/images/thumb/Blueprint.png/32px-Blueprint.png"},{"name":"Deconstruction planner","href":"/Deconstruction_planner","image":"/images/thumb/Deconstruction_planner.png/32px-Deconstruction_planner.png"},{"name":"Upgrade planner","href":"/Upgrade_planner","image":"/images/thumb/Upgrade_planner.png/32px-Upgrade_planner.png"},{"name":"Blueprint book","href":"/Blueprint_book","image":"/images/thumb/Blueprint_book.png/32px-Blueprint_book.png"},{"name":"Boiler","href":"/Boiler","image":"/images/thumb/Boiler.png/32px-Boiler.png"},{"name":"Steam engine","href":"/Steam_engine","image":"/images/thumb/Steam_engine.png/32px-Steam_engine.png"},{"name":"Solar panel","href":"/Solar_panel","image":"/images/thumb/Solar_panel.png/32px-Solar_panel.png"},{"name":"Accumulator","href":"/Accumulator","image":"/images/thumb/Accumulator.png/32px-Accumulator.png"},{"name":"Nuclear reactor","href":"/Nuclear_reactor","image":"/images/thumb/Nuclear_reactor.png/32px-Nuclear_reactor.png"},{"name":"Heat pipe","href":"/Heat_pipe","image":"/images/thumb/Heat_pipe.png/32px-Heat_pipe.png"},{"name":"Heat exchanger","href":"/Heat_exchanger","image":"/images/thumb/Heat_exchanger.png/32px-Heat_exchanger.png"},{"name":"Steam turbine","href":"/Steam_turbine","image":"/images/thumb/Steam_turbine.png/32px-Steam_turbine.png"},{"name":"Burner mining drill","href":"/Burner_mining_drill","image":"/images/thumb/Burner_mining_drill.png/32px-Burner_mining_drill.png"},{"name":"Electric mining drill","href":"/Electric_mining_drill","image":"/images/thumb/Electric_mining_drill.png/32px-Electric_mining_drill.png"},{"name":"Offshore pump","href":"/Offshore_pump","image":"/images/thumb/Offshore_pump.png/32px-Offshore_pump.png"},{"name":"Pumpjack","href":"/Pumpjack","image":"/images/thumb/Pumpjack.png/32px-Pumpjack.png"},{"name":"Stone furnace","href":"/Stone_furnace","image":"/images/thumb/Stone_furnace.png/32px-Stone_furnace.png"},{"name":"Steel furnace","href":"/Steel_furnace","image":"/images/thumb/Steel_furnace.png/32px-Steel_furnace.png"},{"name":"Electric furnace","href":"/Electric_furnace","image":"/images/thumb/Electric_furnace.png/32px-Electric_furnace.png"},{"name":"Assembling machine 1","href":"/Assembling_machine_1","image":"/images/thumb/Assembling_machine_1.png/32px-Assembling_machine_1.png"},{"name":"Assembling machine 2","href":"/Assembling_machine_2","image":"/images/thumb/Assembling_machine_2.png/32px-Assembling_machine_2.png"},{"name":"Assembling machine 3","href":"/Assembling_machine_3","image":"/images/thumb/Assembling_machine_3.png/32px-Assembling_machine_3.png"},{"name":"Oil refinery","href":"/Oil_refinery","image":"/images/thumb/Oil_refinery.png/32px-Oil_refinery.png"},{"name":"Chemical plant","href":"/Chemical_plant","image":"/images/thumb/Chemical_plant.png/32px-Chemical_plant.png"},{"name":"Centrifuge","href":"/Centrifuge","image":"/images/thumb/Centrifuge.png/32px-Centrifuge.png"},{"name":"Lab","href":"/Lab","image":"/images/thumb/Lab.png/32px-Lab.png"},{"name":"Beacon","href":"/Beacon","image":"/images/thumb/Beacon.png/32px-Beacon.png"},{"name":"Speed module","href":"/Speed_module","image":"/images/thumb/Speed_module.png/32px-Speed_module.png"},{"name":"Speed module 2","href":"/Speed_module_2","image":"/images/thumb/Speed_module_2.png/32px-Speed_module_2.png"},{"name":"Speed module 3","href":"/Speed_module_3","image":"/images/thumb/Speed_module_3.png/32px-Speed_module_3.png"},{"name":"Efficiency module","href":"/Efficiency_module","image":"/images/thumb/Efficiency_module.png/32px-Efficiency_module.png"},{"name":"Efficiency module 2","href":"/Efficiency_module_2","image":"/images/thumb/Efficiency_module_2.png/32px-Efficiency_module_2.png"},{"name":"Efficiency module 3","href":"/Efficiency_module_3","image":"/images/thumb/Efficiency_module_3.png/32px-Efficiency_module_3.png"},{"name":"Productivity module","href":"/Productivity_module","image":"/images/thumb/Productivity_module.png/32px-Productivity_module.png"},{"name":"Productivity module 2","href":"/Productivity_module_2","image":"/images/thumb/Productivity_module_2.png/32px-Productivity_module_2.png"},{"name":"Productivity module 3","href":"/Productivity_module_3","image":"/images/thumb/Productivity_module_3.png/32px-Productivity_module_3.png"},{"name":"Rocket silo","href":"/Rocket_silo","image":"/images/thumb/Rocket_silo.png/32px-Rocket_silo.png"},{"name":"Satellite","href":"/Satellite","image":"/images/thumb/Satellite.png/32px-Satellite.png"},{"name":"Crude oil","href":"/Crude_oil","image":"/images/thumb/Crude_oil.png/32px-Crude_oil.png"},{"name":"Heavy oil","href":"/Heavy_oil","image":"/images/thumb/Heavy_oil.png/32px-Heavy_oil.png"},{"name":"Light oil","href":"/Light_oil","image":"/images/thumb/Light_oil.png/32px-Light_oil.png"},{"name":"Lubricant","href":"/Lubricant","image":"/images/thumb/Lubricant.png/32px-Lubricant.png"},{"name":"Petroleum gas","href":"/Petroleum_gas","image":"/images/thumb/Petroleum_gas.png/32px-Petroleum_gas.png"},{"name":"Sulfuric acid","href":"/Sulfuric_acid","image":"/images/thumb/Sulfuric_acid.png/32px-Sulfuric_acid.png"},{"name":"Water","href":"/Water","image":"/images/thumb/Water.png/32px-Water.png"},{"name":"Steam","href":"/Steam","image":"/images/thumb/Steam.png/32px-Steam.png"},{"name":"Wood","href":"/Wood","image":"/images/thumb/Wood.png/32px-Wood.png"},{"name":"Coal","href":"/Coal","image":"/images/thumb/Coal.png/32px-Coal.png"},{"name":"Stone","href":"/Stone","image":"/images/thumb/Stone.png/32px-Stone.png"},{"name":"Iron ore","href":"/Iron_ore","image":"/images/thumb/Iron_ore.png/32px-Iron_ore.png"},{"name":"Copper ore","href":"/Copper_ore","image":"/images/thumb/Copper_ore.png/32px-Copper_ore.png"},{"name":"Uranium ore","href":"/Uranium_ore","image":"/images/thumb/Uranium_ore.png/32px-Uranium_ore.png"},{"name":"Raw fish","href":"/Raw_fish","image":"/images/thumb/Raw_fish.png/32px-Raw_fish.png"},{"name":"Iron plate","href":"/Iron_plate","image":"/images/thumb/Iron_plate.png/32px-Iron_plate.png"},{"name":"Copper plate","href":"/Copper_plate","image":"/images/thumb/Copper_plate.png/32px-Copper_plate.png"},{"name":"Solid fuel","href":"/Solid_fuel","image":"/images/thumb/Solid_fuel.png/32px-Solid_fuel.png"},{"name":"Steel plate","href":"/Steel_plate","image":"/images/thumb/Steel_plate.png/32px-Steel_plate.png"},{"name":"Plastic bar","href":"/Plastic_bar","image":"/images/thumb/Plastic_bar.png/32px-Plastic_bar.png"},{"name":"Sulfur","href":"/Sulfur","image":"/images/thumb/Sulfur.png/32px-Sulfur.png"},{"name":"Battery","href":"/Battery","image":"/images/thumb/Battery.png/32px-Battery.png"},{"name":"Explosives","href":"/Explosives","image":"/images/thumb/Explosives.png/32px-Explosives.png"},{"name":"Uranium processing","href":"/Uranium_processing","image":"/images/thumb/Uranium_processing.png/32px-Uranium_processing.png"},{"name":"Crude oil barrel","href":"/Crude_oil_barrel","image":"/images/thumb/Crude_oil_barrel.png/32px-Crude_oil_barrel.png"},{"name":"Heavy oil barrel","href":"/Heavy_oil_barrel","image":"/images/thumb/Heavy_oil_barrel.png/32px-Heavy_oil_barrel.png"},{"name":"Light oil barrel","href":"/Light_oil_barrel","image":"/images/thumb/Light_oil_barrel.png/32px-Light_oil_barrel.png"},{"name":"Lubricant barrel","href":"/Lubricant_barrel","image":"/images/thumb/Lubricant_barrel.png/32px-Lubricant_barrel.png"},{"name":"Petroleum gas barrel","href":"/Petroleum_gas_barrel","image":"/images/thumb/Petroleum_gas_barrel.png/32px-Petroleum_gas_barrel.png"},{"name":"Sulfuric acid barrel","href":"/Sulfuric_acid_barrel","image":"/images/thumb/Sulfuric_acid_barrel.png/32px-Sulfuric_acid_barrel.png"},{"name":"Water barrel","href":"/Water_barrel","image":"/images/thumb/Water_barrel.png/32px-Water_barrel.png"},{"name":"Copper cable","href":"/Copper_cable","image":"/images/thumb/Copper_cable.png/32px-Copper_cable.png"},{"name":"Iron stick","href":"/Iron_stick","image":"/images/thumb/Iron_stick.png/32px-Iron_stick.png"},{"name":"Iron gear wheel","href":"/Iron_gear_wheel","image":"/images/thumb/Iron_gear_wheel.png/32px-Iron_gear_wheel.png"},{"name":"Empty barrel","href":"/Empty_barrel","image":"/images/thumb/Empty_barrel.png/32px-Empty_barrel.png"},{"name":"Electronic circuit","href":"/Electronic_circuit","image":"/images/thumb/Electronic_circuit.png/32px-Electronic_circuit.png"},{"name":"Advanced circuit","href":"/Advanced_circuit","image":"/images/thumb/Advanced_circuit.png/32px-Advanced_circuit.png"},{"name":"Processing unit","href":"/Processing_unit","image":"/images/thumb/Processing_unit.png/32px-Processing_unit.png"},{"name":"Engine unit","href":"/Engine_unit","image":"/images/thumb/Engine_unit.png/32px-Engine_unit.png"},{"name":"Electric engine unit","href":"/Electric_engine_unit","image":"/images/thumb/Electric_engine_unit.png/32px-Electric_engine_unit.png"},{"name":"Flying robot frame","href":"/Flying_robot_frame","image":"/images/thumb/Flying_robot_frame.png/32px-Flying_robot_frame.png"},{"name":"Rocket part","href":"/Rocket_part","image":"/images/thumb/Rocket_part.png/32px-Rocket_part.png"},{"name":"Rocket control unit","href":"/Rocket_control_unit","image":"/images/thumb/Rocket_control_unit.png/32px-Rocket_control_unit.png"},{"name":"Low density structure","href":"/Low_density_structure","image":"/images/thumb/Low_density_structure.png/32px-Low_density_structure.png"},{"name":"Rocket fuel","href":"/Rocket_fuel","image":"/images/thumb/Rocket_fuel.png/32px-Rocket_fuel.png"},{"name":"Nuclear fuel","href":"/Nuclear_fuel","image":"/images/thumb/Nuclear_fuel.png/32px-Nuclear_fuel.png"},{"name":"Uranium-235","href":"/Uranium-235","image":"/images/thumb/Uranium-235.png/32px-Uranium-235.png"},{"name":"Uranium-238","href":"/Uranium-238","image":"/images/thumb/Uranium-238.png/32px-Uranium-238.png"},{"name":"Uranium fuel cell","href":"/Uranium_fuel_cell","image":"/images/thumb/Uranium_fuel_cell.png/32px-Uranium_fuel_cell.png"},{"name":"Nuclear fuel reprocessing","href":"/Nuclear_fuel_reprocessing","image":"/images/thumb/Nuclear_fuel_reprocessing.png/32px-Nuclear_fuel_reprocessing.png"},{"name":"Kovarex enrichment process","href":"/Kovarex_enrichment_process","image":"/images/thumb/Kovarex_enrichment_process.png/32px-Kovarex_enrichment_process.png"},{"name":"Used up uranium fuel cell","href":"/Used_up_uranium_fuel_cell","image":"/images/thumb/Used_up_uranium_fuel_cell.png/32px-Used_up_uranium_fuel_cell.png"},{"name":"Automation science pack","href":"/Automation_science_pack","image":"/images/thumb/Automation_science_pack.png/32px-Automation_science_pack.png"},{"name":"Logistic science pack","href":"/Logistic_science_pack","image":"/images/thumb/Logistic_science_pack.png/32px-Logistic_science_pack.png"},{"name":"Military science pack","href":"/Military_science_pack","image":"/images/thumb/Military_science_pack.png/32px-Military_science_pack.png"},{"name":"Chemical science pack","href":"/Chemical_science_pack","image":"/images/thumb/Chemical_science_pack.png/32px-Chemical_science_pack.png"},{"name":"Production science pack","href":"/Production_science_pack","image":"/images/thumb/Production_science_pack.png/32px-Production_science_pack.png"},{"name":"Utility science pack","href":"/Utility_science_pack","image":"/images/thumb/Utility_science_pack.png/32px-Utility_science_pack.png"},{"name":"Space science pack","href":"/Space_science_pack","image":"/images/thumb/Space_science_pack.png/32px-Space_science_pack.png"},{"name":"Pistol","href":"/Pistol","image":"/images/thumb/Pistol.png/32px-Pistol.png"},{"name":"Submachine gun","href":"/Submachine_gun","image":"/images/thumb/Submachine_gun.png/32px-Submachine_gun.png"},{"name":"Shotgun","href":"/Shotgun","image":"/images/thumb/Shotgun.png/32px-Shotgun.png"},{"name":"Combat shotgun","href":"/Combat_shotgun","image":"/images/thumb/Combat_shotgun.png/32px-Combat_shotgun.png"},{"name":"Rocket launcher","href":"/Rocket_launcher","image":"/images/thumb/Rocket_launcher.png/32px-Rocket_launcher.png"},{"name":"Flamethrower","href":"/Flamethrower","image":"/images/thumb/Flamethrower.png/32px-Flamethrower.png"},{"name":"Land mine","href":"/Land_mine","image":"/images/thumb/Land_mine.png/32px-Land_mine.png"},{"name":"Firearm magazine","href":"/Firearm_magazine","image":"/images/thumb/Firearm_magazine.png/32px-Firearm_magazine.png"},{"name":"Piercing rounds magazine","href":"/Piercing_rounds_magazine","image":"/images/thumb/Piercing_rounds_magazine.png/32px-Piercing_rounds_magazine.png"},{"name":"Uranium rounds magazine","href":"/Uranium_rounds_magazine","image":"/images/thumb/Uranium_rounds_magazine.png/32px-Uranium_rounds_magazine.png"},{"name":"Shotgun shells","href":"/Shotgun_shells","image":"/images/thumb/Shotgun_shells.png/32px-Shotgun_shells.png"},{"name":"Piercing shotgun shells","href":"/Piercing_shotgun_shells","image":"/images/thumb/Piercing_shotgun_shells.png/32px-Piercing_shotgun_shells.png"},{"name":"Cannon shell","href":"/Cannon_shell","image":"/images/thumb/Cannon_shell.png/32px-Cannon_shell.png"},{"name":"Explosive cannon shell","href":"/Explosive_cannon_shell","image":"/images/thumb/Explosive_cannon_shell.png/32px-Explosive_cannon_shell.png"},{"name":"Uranium cannon shell","href":"/Uranium_cannon_shell","image":"/images/thumb/Uranium_cannon_shell.png/32px-Uranium_cannon_shell.png"},{"name":"Explosive uranium cannon shell","href":"/Explosive_uranium_cannon_shell","image":"/images/thumb/Explosive_uranium_cannon_shell.png/32px-Explosive_uranium_cannon_shell.png"},{"name":"Artillery shell","href":"/Artillery_shell","image":"/images/thumb/Artillery_shell.png/32px-Artillery_shell.png"},{"name":"Rocket","href":"/Rocket","image":"/images/thumb/Rocket.png/32px-Rocket.png"},{"name":"Explosive rocket","href":"/Explosive_rocket","image":"/images/thumb/Explosive_rocket.png/32px-Explosive_rocket.png"},{"name":"Atomic bomb","href":"/Atomic_bomb","image":"/images/thumb/Atomic_bomb.png/32px-Atomic_bomb.png"},{"name":"Flamethrower ammo","href":"/Flamethrower_ammo","image":"/images/thumb/Flamethrower_ammo.png/32px-Flamethrower_ammo.png"},{"name":"Grenade","href":"/Grenade","image":"/images/thumb/Grenade.png/32px-Grenade.png"},{"name":"Cluster grenade","href":"/Cluster_grenade","image":"/images/thumb/Cluster_grenade.png/32px-Cluster_grenade.png"},{"name":"Poison capsule","href":"/Poison_capsule","image":"/images/thumb/Poison_capsule.png/32px-Poison_capsule.png"},{"name":"Slowdown capsule","href":"/Slowdown_capsule","image":"/images/thumb/Slowdown_capsule.png/32px-Slowdown_capsule.png"},{"name":"Defender capsule","href":"/Defender_capsule","image":"/images/thumb/Defender_capsule.png/32px-Defender_capsule.png"},{"name":"Distractor capsule","href":"/Distractor_capsule","image":"/images/thumb/Distractor_capsule.png/32px-Distractor_capsule.png"},{"name":"Destroyer capsule","href":"/Destroyer_capsule","image":"/images/thumb/Destroyer_capsule.png/32px-Destroyer_capsule.png"},{"name":"Light armor","href":"/Light_armor","image":"/images/thumb/Light_armor.png/32px-Light_armor.png"},{"name":"Heavy armor","href":"/Heavy_armor","image":"/images/thumb/Heavy_armor.png/32px-Heavy_armor.png"},{"name":"Modular armor","href":"/Modular_armor","image":"/images/thumb/Modular_armor.png/32px-Modular_armor.png"},{"name":"Power armor","href":"/Power_armor","image":"/images/thumb/Power_armor.png/32px-Power_armor.png"},{"name":"Power armor MK2","href":"/Power_armor_MK2","image":"/images/thumb/Power_armor_MK2.png/32px-Power_armor_MK2.png"},{"name":"Portable solar panel","href":"/Portable_solar_panel","image":"/images/thumb/Portable_solar_panel.png/32px-Portable_solar_panel.png"},{"name":"Portable fusion reactor","href":"/Portable_fusion_reactor","image":"/images/thumb/Portable_fusion_reactor.png/32px-Portable_fusion_reactor.png"},{"name":"Personal battery","href":"/Personal_battery","image":"/images/thumb/Personal_battery.png/32px-Personal_battery.png"},{"name":"Personal battery MK2","href":"/Personal_battery_MK2","image":"/images/thumb/Personal_battery_MK2.png/32px-Personal_battery_MK2.png"},{"name":"Belt immunity equipment","href":"/Belt_immunity_equipment","image":"/images/thumb/Belt_immunity_equipment.png/32px-Belt_immunity_equipment.png"},{"name":"Exoskeleton","href":"/Exoskeleton","image":"/images/thumb/Exoskeleton.png/32px-Exoskeleton.png"},{"name":"Personal roboport","href":"/Personal_roboport","image":"/images/thumb/Personal_roboport.png/32px-Personal_roboport.png"},{"name":"Personal roboport MK2","href":"/Personal_roboport_MK2","image":"/images/thumb/Personal_roboport_MK2.png/32px-Personal_roboport_MK2.png"},{"name":"Nightvision","href":"/Nightvision","image":"/images/thumb/Nightvision.png/32px-Nightvision.png"},{"name":"Energy shield","href":"/Energy_shield","image":"/images/thumb/Energy_shield.png/32px-Energy_shield.png"},{"name":"Energy shield MK2","href":"/Energy_shield_MK2","image":"/images/thumb/Energy_shield_MK2.png/32px-Energy_shield_MK2.png"},{"name":"Personal laser defense","href":"/Personal_laser_defense","image":"/images/thumb/Personal_laser_defense.png/32px-Personal_laser_defense.png"},{"name":"Discharge defense","href":"/Discharge_defense","image":"/images/thumb/Discharge_defense.png/32px-Discharge_defense.png"},{"name":"Discharge defense remote","href":"/Discharge_defense_remote","image":"/images/thumb/Discharge_defense_remote.png/32px-Discharge_defense_remote.png"},{"name":"Wall","href":"/Wall","image":"/images/thumb/Wall.png/32px-Wall.png"},{"name":"Gate","href":"/Gate","image":"/images/thumb/Gate.png/32px-Gate.png"},{"name":"Gun turret","href":"/Gun_turret","image":"/images/thumb/Gun_turret.png/32px-Gun_turret.png"},{"name":"Laser turret","href":"/Laser_turret","image":"/images/thumb/Laser_turret.png/32px-Laser_turret.png"},{"name":"Flamethrower turret","href":"/Flamethrower_turret","image":"/images/thumb/Flamethrower_turret.png/32px-Flamethrower_turret.png"},{"name":"Artillery turret","href":"/Artillery_turret","image":"/images/thumb/Artillery_turret.png/32px-Artillery_turret.png"},{"name":"Artillery targeting remote","href":"/Artillery_targeting_remote","image":"/images/thumb/Artillery_targeting_remote.png/32px-Artillery_targeting_remote.png"},{"name":"Radar","href":"/Radar","image":"/images/thumb/Radar.png/32px-Radar.png"}] \ No newline at end of file +[ + { + "name": "Wooden chest", + "href": "/Wooden_chest", + "image": "/images/thumb/Wooden_chest.png/32px-Wooden_chest.png" + }, + { + "name": "Iron chest", + "href": "/Iron_chest", + "image": "/images/thumb/Iron_chest.png/32px-Iron_chest.png" + }, + { + "name": "Steel chest", + "href": "/Steel_chest", + "image": "/images/thumb/Steel_chest.png/32px-Steel_chest.png" + }, + { + "name": "Storage tank", + "href": "/Storage_tank", + "image": "/images/thumb/Storage_tank.png/32px-Storage_tank.png" + }, + { + "name": "Transport belt", + "href": "/Transport_belt", + "image": "/images/thumb/Transport_belt.png/32px-Transport_belt.png" + }, + { + "name": "Fast transport belt", + "href": "/Fast_transport_belt", + "image": "/images/thumb/Fast_transport_belt.png/32px-Fast_transport_belt.png" + }, + { + "name": "Express transport belt", + "href": "/Express_transport_belt", + "image": "/images/thumb/Express_transport_belt.png/32px-Express_transport_belt.png" + }, + { + "name": "Underground belt", + "href": "/Underground_belt", + "image": "/images/thumb/Underground_belt.png/32px-Underground_belt.png" + }, + { + "name": "Fast underground belt", + "href": "/Fast_underground_belt", + "image": "/images/thumb/Fast_underground_belt.png/32px-Fast_underground_belt.png" + }, + { + "name": "Express underground belt", + "href": "/Express_underground_belt", + "image": "/images/thumb/Express_underground_belt.png/32px-Express_underground_belt.png" + }, + { + "name": "Splitter", + "href": "/Splitter", + "image": "/images/thumb/Splitter.png/32px-Splitter.png" + }, + { + "name": "Fast splitter", + "href": "/Fast_splitter", + "image": "/images/thumb/Fast_splitter.png/32px-Fast_splitter.png" + }, + { + "name": "Express splitter", + "href": "/Express_splitter", + "image": "/images/thumb/Express_splitter.png/32px-Express_splitter.png" + }, + { + "name": "Burner inserter", + "href": "/Burner_inserter", + "image": "/images/thumb/Burner_inserter.png/32px-Burner_inserter.png" + }, + { + "name": "Inserter", + "href": "/Inserter", + "image": "/images/thumb/Inserter.png/32px-Inserter.png" + }, + { + "name": "Long-handed inserter", + "href": "/Long-handed_inserter", + "image": "/images/thumb/Long-handed_inserter.png/32px-Long-handed_inserter.png" + }, + { + "name": "Fast inserter", + "href": "/Fast_inserter", + "image": "/images/thumb/Fast_inserter.png/32px-Fast_inserter.png" + }, + { + "name": "Filter inserter", + "href": "/Filter_inserter", + "image": "/images/thumb/Filter_inserter.png/32px-Filter_inserter.png" + }, + { + "name": "Stack inserter", + "href": "/Stack_inserter", + "image": "/images/thumb/Stack_inserter.png/32px-Stack_inserter.png" + }, + { + "name": "Stack filter inserter", + "href": "/Stack_filter_inserter", + "image": "/images/thumb/Stack_filter_inserter.png/32px-Stack_filter_inserter.png" + }, + { + "name": "Small electric pole", + "href": "/Small_electric_pole", + "image": "/images/thumb/Small_electric_pole.png/32px-Small_electric_pole.png" + }, + { + "name": "Medium electric pole", + "href": "/Medium_electric_pole", + "image": "/images/thumb/Medium_electric_pole.png/32px-Medium_electric_pole.png" + }, + { + "name": "Big electric pole", + "href": "/Big_electric_pole", + "image": "/images/thumb/Big_electric_pole.png/32px-Big_electric_pole.png" + }, + { + "name": "Substation", + "href": "/Substation", + "image": "/images/thumb/Substation.png/32px-Substation.png" + }, + { "name": "Pipe", "href": "/Pipe", "image": "/images/thumb/Pipe.png/32px-Pipe.png" }, + { + "name": "Pipe to ground", + "href": "/Pipe_to_ground", + "image": "/images/thumb/Pipe_to_ground.png/32px-Pipe_to_ground.png" + }, + { "name": "Pump", "href": "/Pump", "image": "/images/thumb/Pump.png/32px-Pump.png" }, + { + "name": "Rail", + "href": "/Rail", + "image": "/images/thumb/Straight_rail.png/32px-Straight_rail.png" + }, + { + "name": "Train stop", + "href": "/Train_stop", + "image": "/images/thumb/Train_stop.png/32px-Train_stop.png" + }, + { + "name": "Rail signal", + "href": "/Rail_signal", + "image": "/images/thumb/Rail_signal.png/32px-Rail_signal.png" + }, + { + "name": "Rail chain signal", + "href": "/Rail_chain_signal", + "image": "/images/thumb/Rail_chain_signal.png/32px-Rail_chain_signal.png" + }, + { + "name": "Locomotive", + "href": "/Locomotive", + "image": "/images/thumb/Locomotive.png/32px-Locomotive.png" + }, + { + "name": "Cargo wagon", + "href": "/Cargo_wagon", + "image": "/images/thumb/Cargo_wagon.png/32px-Cargo_wagon.png" + }, + { + "name": "Fluid wagon", + "href": "/Fluid_wagon", + "image": "/images/thumb/Fluid_wagon.png/32px-Fluid_wagon.png" + }, + { + "name": "Artillery wagon", + "href": "/Artillery_wagon", + "image": "/images/thumb/Artillery_wagon.png/32px-Artillery_wagon.png" + }, + { "name": "Car", "href": "/Car", "image": "/images/thumb/Car.png/32px-Car.png" }, + { "name": "Tank", "href": "/Tank", "image": "/images/thumb/Tank.png/32px-Tank.png" }, + { + "name": "Spidertron", + "href": "/Spidertron", + "image": "/images/thumb/Spidertron.png/32px-Spidertron.png" + }, + { + "name": "Spidertron remote", + "href": "/Spidertron_remote", + "image": "/images/thumb/Spidertron_remote.png/32px-Spidertron_remote.png" + }, + { + "name": "Logistic robot", + "href": "/Logistic_robot", + "image": "/images/thumb/Logistic_robot.png/32px-Logistic_robot.png" + }, + { + "name": "Construction robot", + "href": "/Construction_robot", + "image": "/images/thumb/Construction_robot.png/32px-Construction_robot.png" + }, + { + "name": "Active provider chest", + "href": "/Active_provider_chest", + "image": "/images/thumb/Active_provider_chest.png/32px-Active_provider_chest.png" + }, + { + "name": "Passive provider chest", + "href": "/Passive_provider_chest", + "image": "/images/thumb/Passive_provider_chest.png/32px-Passive_provider_chest.png" + }, + { + "name": "Storage chest", + "href": "/Storage_chest", + "image": "/images/thumb/Storage_chest.png/32px-Storage_chest.png" + }, + { + "name": "Buffer chest", + "href": "/Buffer_chest", + "image": "/images/thumb/Buffer_chest.png/32px-Buffer_chest.png" + }, + { + "name": "Requester chest", + "href": "/Requester_chest", + "image": "/images/thumb/Requester_chest.png/32px-Requester_chest.png" + }, + { + "name": "Roboport", + "href": "/Roboport", + "image": "/images/thumb/Roboport.png/32px-Roboport.png" + }, + { "name": "Lamp", "href": "/Lamp", "image": "/images/thumb/Lamp.png/32px-Lamp.png" }, + { + "name": "Red wire", + "href": "/Red_wire", + "image": "/images/thumb/Red_wire.png/32px-Red_wire.png" + }, + { + "name": "Green wire", + "href": "/Green_wire", + "image": "/images/thumb/Green_wire.png/32px-Green_wire.png" + }, + { + "name": "Arithmetic combinator", + "href": "/Arithmetic_combinator", + "image": "/images/thumb/Arithmetic_combinator.png/32px-Arithmetic_combinator.png" + }, + { + "name": "Decider combinator", + "href": "/Decider_combinator", + "image": "/images/thumb/Decider_combinator.png/32px-Decider_combinator.png" + }, + { + "name": "Constant combinator", + "href": "/Constant_combinator", + "image": "/images/thumb/Constant_combinator.png/32px-Constant_combinator.png" + }, + { + "name": "Power switch", + "href": "/Power_switch", + "image": "/images/thumb/Power_switch.png/32px-Power_switch.png" + }, + { + "name": "Programmable speaker", + "href": "/Programmable_speaker", + "image": "/images/thumb/Programmable_speaker.png/32px-Programmable_speaker.png" + }, + { + "name": "Stone brick", + "href": "/Stone_brick", + "image": "/images/thumb/Stone_brick.png/32px-Stone_brick.png" + }, + { + "name": "Concrete", + "href": "/Concrete", + "image": "/images/thumb/Concrete.png/32px-Concrete.png" + }, + { + "name": "Hazard concrete", + "href": "/Hazard_concrete", + "image": "/images/thumb/Hazard_concrete.png/32px-Hazard_concrete.png" + }, + { + "name": "Refined concrete", + "href": "/Refined_concrete", + "image": "/images/thumb/Refined_concrete.png/32px-Refined_concrete.png" + }, + { + "name": "Refined hazard concrete", + "href": "/Refined_hazard_concrete", + "image": "/images/thumb/Refined_hazard_concrete.png/32px-Refined_hazard_concrete.png" + }, + { + "name": "Landfill", + "href": "/Landfill", + "image": "/images/thumb/Landfill.png/32px-Landfill.png" + }, + { + "name": "Cliff explosives", + "href": "/Cliff_explosives", + "image": "/images/thumb/Cliff_explosives.png/32px-Cliff_explosives.png" + }, + { + "name": "Repair pack", + "href": "/Repair_pack", + "image": "/images/thumb/Repair_pack.png/32px-Repair_pack.png" + }, + { + "name": "Blueprint", + "href": "/Blueprint", + "image": "/images/thumb/Blueprint.png/32px-Blueprint.png" + }, + { + "name": "Deconstruction planner", + "href": "/Deconstruction_planner", + "image": "/images/thumb/Deconstruction_planner.png/32px-Deconstruction_planner.png" + }, + { + "name": "Upgrade planner", + "href": "/Upgrade_planner", + "image": "/images/thumb/Upgrade_planner.png/32px-Upgrade_planner.png" + }, + { + "name": "Blueprint book", + "href": "/Blueprint_book", + "image": "/images/thumb/Blueprint_book.png/32px-Blueprint_book.png" + }, + { "name": "Boiler", "href": "/Boiler", "image": "/images/thumb/Boiler.png/32px-Boiler.png" }, + { + "name": "Steam engine", + "href": "/Steam_engine", + "image": "/images/thumb/Steam_engine.png/32px-Steam_engine.png" + }, + { + "name": "Solar panel", + "href": "/Solar_panel", + "image": "/images/thumb/Solar_panel.png/32px-Solar_panel.png" + }, + { + "name": "Accumulator", + "href": "/Accumulator", + "image": "/images/thumb/Accumulator.png/32px-Accumulator.png" + }, + { + "name": "Nuclear reactor", + "href": "/Nuclear_reactor", + "image": "/images/thumb/Nuclear_reactor.png/32px-Nuclear_reactor.png" + }, + { + "name": "Heat pipe", + "href": "/Heat_pipe", + "image": "/images/thumb/Heat_pipe.png/32px-Heat_pipe.png" + }, + { + "name": "Heat exchanger", + "href": "/Heat_exchanger", + "image": "/images/thumb/Heat_exchanger.png/32px-Heat_exchanger.png" + }, + { + "name": "Steam turbine", + "href": "/Steam_turbine", + "image": "/images/thumb/Steam_turbine.png/32px-Steam_turbine.png" + }, + { + "name": "Burner mining drill", + "href": "/Burner_mining_drill", + "image": "/images/thumb/Burner_mining_drill.png/32px-Burner_mining_drill.png" + }, + { + "name": "Electric mining drill", + "href": "/Electric_mining_drill", + "image": "/images/thumb/Electric_mining_drill.png/32px-Electric_mining_drill.png" + }, + { + "name": "Offshore pump", + "href": "/Offshore_pump", + "image": "/images/thumb/Offshore_pump.png/32px-Offshore_pump.png" + }, + { + "name": "Pumpjack", + "href": "/Pumpjack", + "image": "/images/thumb/Pumpjack.png/32px-Pumpjack.png" + }, + { + "name": "Stone furnace", + "href": "/Stone_furnace", + "image": "/images/thumb/Stone_furnace.png/32px-Stone_furnace.png" + }, + { + "name": "Steel furnace", + "href": "/Steel_furnace", + "image": "/images/thumb/Steel_furnace.png/32px-Steel_furnace.png" + }, + { + "name": "Electric furnace", + "href": "/Electric_furnace", + "image": "/images/thumb/Electric_furnace.png/32px-Electric_furnace.png" + }, + { + "name": "Assembling machine 1", + "href": "/Assembling_machine_1", + "image": "/images/thumb/Assembling_machine_1.png/32px-Assembling_machine_1.png" + }, + { + "name": "Assembling machine 2", + "href": "/Assembling_machine_2", + "image": "/images/thumb/Assembling_machine_2.png/32px-Assembling_machine_2.png" + }, + { + "name": "Assembling machine 3", + "href": "/Assembling_machine_3", + "image": "/images/thumb/Assembling_machine_3.png/32px-Assembling_machine_3.png" + }, + { + "name": "Oil refinery", + "href": "/Oil_refinery", + "image": "/images/thumb/Oil_refinery.png/32px-Oil_refinery.png" + }, + { + "name": "Chemical plant", + "href": "/Chemical_plant", + "image": "/images/thumb/Chemical_plant.png/32px-Chemical_plant.png" + }, + { + "name": "Centrifuge", + "href": "/Centrifuge", + "image": "/images/thumb/Centrifuge.png/32px-Centrifuge.png" + }, + { "name": "Lab", "href": "/Lab", "image": "/images/thumb/Lab.png/32px-Lab.png" }, + { "name": "Beacon", "href": "/Beacon", "image": "/images/thumb/Beacon.png/32px-Beacon.png" }, + { + "name": "Speed module", + "href": "/Speed_module", + "image": "/images/thumb/Speed_module.png/32px-Speed_module.png" + }, + { + "name": "Speed module 2", + "href": "/Speed_module_2", + "image": "/images/thumb/Speed_module_2.png/32px-Speed_module_2.png" + }, + { + "name": "Speed module 3", + "href": "/Speed_module_3", + "image": "/images/thumb/Speed_module_3.png/32px-Speed_module_3.png" + }, + { + "name": "Efficiency module", + "href": "/Efficiency_module", + "image": "/images/thumb/Efficiency_module.png/32px-Efficiency_module.png" + }, + { + "name": "Efficiency module 2", + "href": "/Efficiency_module_2", + "image": "/images/thumb/Efficiency_module_2.png/32px-Efficiency_module_2.png" + }, + { + "name": "Efficiency module 3", + "href": "/Efficiency_module_3", + "image": "/images/thumb/Efficiency_module_3.png/32px-Efficiency_module_3.png" + }, + { + "name": "Productivity module", + "href": "/Productivity_module", + "image": "/images/thumb/Productivity_module.png/32px-Productivity_module.png" + }, + { + "name": "Productivity module 2", + "href": "/Productivity_module_2", + "image": "/images/thumb/Productivity_module_2.png/32px-Productivity_module_2.png" + }, + { + "name": "Productivity module 3", + "href": "/Productivity_module_3", + "image": "/images/thumb/Productivity_module_3.png/32px-Productivity_module_3.png" + }, + { + "name": "Rocket silo", + "href": "/Rocket_silo", + "image": "/images/thumb/Rocket_silo.png/32px-Rocket_silo.png" + }, + { + "name": "Satellite", + "href": "/Satellite", + "image": "/images/thumb/Satellite.png/32px-Satellite.png" + }, + { + "name": "Crude oil", + "href": "/Crude_oil", + "image": "/images/thumb/Crude_oil.png/32px-Crude_oil.png" + }, + { + "name": "Heavy oil", + "href": "/Heavy_oil", + "image": "/images/thumb/Heavy_oil.png/32px-Heavy_oil.png" + }, + { + "name": "Light oil", + "href": "/Light_oil", + "image": "/images/thumb/Light_oil.png/32px-Light_oil.png" + }, + { + "name": "Lubricant", + "href": "/Lubricant", + "image": "/images/thumb/Lubricant.png/32px-Lubricant.png" + }, + { + "name": "Petroleum gas", + "href": "/Petroleum_gas", + "image": "/images/thumb/Petroleum_gas.png/32px-Petroleum_gas.png" + }, + { + "name": "Sulfuric acid", + "href": "/Sulfuric_acid", + "image": "/images/thumb/Sulfuric_acid.png/32px-Sulfuric_acid.png" + }, + { "name": "Water", "href": "/Water", "image": "/images/thumb/Water.png/32px-Water.png" }, + { "name": "Steam", "href": "/Steam", "image": "/images/thumb/Steam.png/32px-Steam.png" }, + { "name": "Wood", "href": "/Wood", "image": "/images/thumb/Wood.png/32px-Wood.png" }, + { "name": "Coal", "href": "/Coal", "image": "/images/thumb/Coal.png/32px-Coal.png" }, + { "name": "Stone", "href": "/Stone", "image": "/images/thumb/Stone.png/32px-Stone.png" }, + { + "name": "Iron ore", + "href": "/Iron_ore", + "image": "/images/thumb/Iron_ore.png/32px-Iron_ore.png" + }, + { + "name": "Copper ore", + "href": "/Copper_ore", + "image": "/images/thumb/Copper_ore.png/32px-Copper_ore.png" + }, + { + "name": "Uranium ore", + "href": "/Uranium_ore", + "image": "/images/thumb/Uranium_ore.png/32px-Uranium_ore.png" + }, + { + "name": "Raw fish", + "href": "/Raw_fish", + "image": "/images/thumb/Raw_fish.png/32px-Raw_fish.png" + }, + { + "name": "Iron plate", + "href": "/Iron_plate", + "image": "/images/thumb/Iron_plate.png/32px-Iron_plate.png" + }, + { + "name": "Copper plate", + "href": "/Copper_plate", + "image": "/images/thumb/Copper_plate.png/32px-Copper_plate.png" + }, + { + "name": "Solid fuel", + "href": "/Solid_fuel", + "image": "/images/thumb/Solid_fuel.png/32px-Solid_fuel.png" + }, + { + "name": "Steel plate", + "href": "/Steel_plate", + "image": "/images/thumb/Steel_plate.png/32px-Steel_plate.png" + }, + { + "name": "Plastic bar", + "href": "/Plastic_bar", + "image": "/images/thumb/Plastic_bar.png/32px-Plastic_bar.png" + }, + { "name": "Sulfur", "href": "/Sulfur", "image": "/images/thumb/Sulfur.png/32px-Sulfur.png" }, + { "name": "Battery", "href": "/Battery", "image": "/images/thumb/Battery.png/32px-Battery.png" }, + { + "name": "Explosives", + "href": "/Explosives", + "image": "/images/thumb/Explosives.png/32px-Explosives.png" + }, + { + "name": "Uranium processing", + "href": "/Uranium_processing", + "image": "/images/thumb/Uranium_processing.png/32px-Uranium_processing.png" + }, + { + "name": "Crude oil barrel", + "href": "/Crude_oil_barrel", + "image": "/images/thumb/Crude_oil_barrel.png/32px-Crude_oil_barrel.png" + }, + { + "name": "Heavy oil barrel", + "href": "/Heavy_oil_barrel", + "image": "/images/thumb/Heavy_oil_barrel.png/32px-Heavy_oil_barrel.png" + }, + { + "name": "Light oil barrel", + "href": "/Light_oil_barrel", + "image": "/images/thumb/Light_oil_barrel.png/32px-Light_oil_barrel.png" + }, + { + "name": "Lubricant barrel", + "href": "/Lubricant_barrel", + "image": "/images/thumb/Lubricant_barrel.png/32px-Lubricant_barrel.png" + }, + { + "name": "Petroleum gas barrel", + "href": "/Petroleum_gas_barrel", + "image": "/images/thumb/Petroleum_gas_barrel.png/32px-Petroleum_gas_barrel.png" + }, + { + "name": "Sulfuric acid barrel", + "href": "/Sulfuric_acid_barrel", + "image": "/images/thumb/Sulfuric_acid_barrel.png/32px-Sulfuric_acid_barrel.png" + }, + { + "name": "Water barrel", + "href": "/Water_barrel", + "image": "/images/thumb/Water_barrel.png/32px-Water_barrel.png" + }, + { + "name": "Copper cable", + "href": "/Copper_cable", + "image": "/images/thumb/Copper_cable.png/32px-Copper_cable.png" + }, + { + "name": "Iron stick", + "href": "/Iron_stick", + "image": "/images/thumb/Iron_stick.png/32px-Iron_stick.png" + }, + { + "name": "Iron gear wheel", + "href": "/Iron_gear_wheel", + "image": "/images/thumb/Iron_gear_wheel.png/32px-Iron_gear_wheel.png" + }, + { + "name": "Empty barrel", + "href": "/Empty_barrel", + "image": "/images/thumb/Empty_barrel.png/32px-Empty_barrel.png" + }, + { + "name": "Electronic circuit", + "href": "/Electronic_circuit", + "image": "/images/thumb/Electronic_circuit.png/32px-Electronic_circuit.png" + }, + { + "name": "Advanced circuit", + "href": "/Advanced_circuit", + "image": "/images/thumb/Advanced_circuit.png/32px-Advanced_circuit.png" + }, + { + "name": "Processing unit", + "href": "/Processing_unit", + "image": "/images/thumb/Processing_unit.png/32px-Processing_unit.png" + }, + { + "name": "Engine unit", + "href": "/Engine_unit", + "image": "/images/thumb/Engine_unit.png/32px-Engine_unit.png" + }, + { + "name": "Electric engine unit", + "href": "/Electric_engine_unit", + "image": "/images/thumb/Electric_engine_unit.png/32px-Electric_engine_unit.png" + }, + { + "name": "Flying robot frame", + "href": "/Flying_robot_frame", + "image": "/images/thumb/Flying_robot_frame.png/32px-Flying_robot_frame.png" + }, + { + "name": "Rocket part", + "href": "/Rocket_part", + "image": "/images/thumb/Rocket_part.png/32px-Rocket_part.png" + }, + { + "name": "Rocket control unit", + "href": "/Rocket_control_unit", + "image": "/images/thumb/Rocket_control_unit.png/32px-Rocket_control_unit.png" + }, + { + "name": "Low density structure", + "href": "/Low_density_structure", + "image": "/images/thumb/Low_density_structure.png/32px-Low_density_structure.png" + }, + { + "name": "Rocket fuel", + "href": "/Rocket_fuel", + "image": "/images/thumb/Rocket_fuel.png/32px-Rocket_fuel.png" + }, + { + "name": "Nuclear fuel", + "href": "/Nuclear_fuel", + "image": "/images/thumb/Nuclear_fuel.png/32px-Nuclear_fuel.png" + }, + { + "name": "Uranium-235", + "href": "/Uranium-235", + "image": "/images/thumb/Uranium-235.png/32px-Uranium-235.png" + }, + { + "name": "Uranium-238", + "href": "/Uranium-238", + "image": "/images/thumb/Uranium-238.png/32px-Uranium-238.png" + }, + { + "name": "Uranium fuel cell", + "href": "/Uranium_fuel_cell", + "image": "/images/thumb/Uranium_fuel_cell.png/32px-Uranium_fuel_cell.png" + }, + { + "name": "Nuclear fuel reprocessing", + "href": "/Nuclear_fuel_reprocessing", + "image": "/images/thumb/Nuclear_fuel_reprocessing.png/32px-Nuclear_fuel_reprocessing.png" + }, + { + "name": "Kovarex enrichment process", + "href": "/Kovarex_enrichment_process", + "image": "/images/thumb/Kovarex_enrichment_process.png/32px-Kovarex_enrichment_process.png" + }, + { + "name": "Used up uranium fuel cell", + "href": "/Used_up_uranium_fuel_cell", + "image": "/images/thumb/Used_up_uranium_fuel_cell.png/32px-Used_up_uranium_fuel_cell.png" + }, + { + "name": "Automation science pack", + "href": "/Automation_science_pack", + "image": "/images/thumb/Automation_science_pack.png/32px-Automation_science_pack.png" + }, + { + "name": "Logistic science pack", + "href": "/Logistic_science_pack", + "image": "/images/thumb/Logistic_science_pack.png/32px-Logistic_science_pack.png" + }, + { + "name": "Military science pack", + "href": "/Military_science_pack", + "image": "/images/thumb/Military_science_pack.png/32px-Military_science_pack.png" + }, + { + "name": "Chemical science pack", + "href": "/Chemical_science_pack", + "image": "/images/thumb/Chemical_science_pack.png/32px-Chemical_science_pack.png" + }, + { + "name": "Production science pack", + "href": "/Production_science_pack", + "image": "/images/thumb/Production_science_pack.png/32px-Production_science_pack.png" + }, + { + "name": "Utility science pack", + "href": "/Utility_science_pack", + "image": "/images/thumb/Utility_science_pack.png/32px-Utility_science_pack.png" + }, + { + "name": "Space science pack", + "href": "/Space_science_pack", + "image": "/images/thumb/Space_science_pack.png/32px-Space_science_pack.png" + }, + { "name": "Pistol", "href": "/Pistol", "image": "/images/thumb/Pistol.png/32px-Pistol.png" }, + { + "name": "Submachine gun", + "href": "/Submachine_gun", + "image": "/images/thumb/Submachine_gun.png/32px-Submachine_gun.png" + }, + { "name": "Shotgun", "href": "/Shotgun", "image": "/images/thumb/Shotgun.png/32px-Shotgun.png" }, + { + "name": "Combat shotgun", + "href": "/Combat_shotgun", + "image": "/images/thumb/Combat_shotgun.png/32px-Combat_shotgun.png" + }, + { + "name": "Rocket launcher", + "href": "/Rocket_launcher", + "image": "/images/thumb/Rocket_launcher.png/32px-Rocket_launcher.png" + }, + { + "name": "Flamethrower", + "href": "/Flamethrower", + "image": "/images/thumb/Flamethrower.png/32px-Flamethrower.png" + }, + { + "name": "Land mine", + "href": "/Land_mine", + "image": "/images/thumb/Land_mine.png/32px-Land_mine.png" + }, + { + "name": "Firearm magazine", + "href": "/Firearm_magazine", + "image": "/images/thumb/Firearm_magazine.png/32px-Firearm_magazine.png" + }, + { + "name": "Piercing rounds magazine", + "href": "/Piercing_rounds_magazine", + "image": "/images/thumb/Piercing_rounds_magazine.png/32px-Piercing_rounds_magazine.png" + }, + { + "name": "Uranium rounds magazine", + "href": "/Uranium_rounds_magazine", + "image": "/images/thumb/Uranium_rounds_magazine.png/32px-Uranium_rounds_magazine.png" + }, + { + "name": "Shotgun shells", + "href": "/Shotgun_shells", + "image": "/images/thumb/Shotgun_shells.png/32px-Shotgun_shells.png" + }, + { + "name": "Piercing shotgun shells", + "href": "/Piercing_shotgun_shells", + "image": "/images/thumb/Piercing_shotgun_shells.png/32px-Piercing_shotgun_shells.png" + }, + { + "name": "Cannon shell", + "href": "/Cannon_shell", + "image": "/images/thumb/Cannon_shell.png/32px-Cannon_shell.png" + }, + { + "name": "Explosive cannon shell", + "href": "/Explosive_cannon_shell", + "image": "/images/thumb/Explosive_cannon_shell.png/32px-Explosive_cannon_shell.png" + }, + { + "name": "Uranium cannon shell", + "href": "/Uranium_cannon_shell", + "image": "/images/thumb/Uranium_cannon_shell.png/32px-Uranium_cannon_shell.png" + }, + { + "name": "Explosive uranium cannon shell", + "href": "/Explosive_uranium_cannon_shell", + "image": "/images/thumb/Explosive_uranium_cannon_shell.png/32px-Explosive_uranium_cannon_shell.png" + }, + { + "name": "Artillery shell", + "href": "/Artillery_shell", + "image": "/images/thumb/Artillery_shell.png/32px-Artillery_shell.png" + }, + { "name": "Rocket", "href": "/Rocket", "image": "/images/thumb/Rocket.png/32px-Rocket.png" }, + { + "name": "Explosive rocket", + "href": "/Explosive_rocket", + "image": "/images/thumb/Explosive_rocket.png/32px-Explosive_rocket.png" + }, + { + "name": "Atomic bomb", + "href": "/Atomic_bomb", + "image": "/images/thumb/Atomic_bomb.png/32px-Atomic_bomb.png" + }, + { + "name": "Flamethrower ammo", + "href": "/Flamethrower_ammo", + "image": "/images/thumb/Flamethrower_ammo.png/32px-Flamethrower_ammo.png" + }, + { "name": "Grenade", "href": "/Grenade", "image": "/images/thumb/Grenade.png/32px-Grenade.png" }, + { + "name": "Cluster grenade", + "href": "/Cluster_grenade", + "image": "/images/thumb/Cluster_grenade.png/32px-Cluster_grenade.png" + }, + { + "name": "Poison capsule", + "href": "/Poison_capsule", + "image": "/images/thumb/Poison_capsule.png/32px-Poison_capsule.png" + }, + { + "name": "Slowdown capsule", + "href": "/Slowdown_capsule", + "image": "/images/thumb/Slowdown_capsule.png/32px-Slowdown_capsule.png" + }, + { + "name": "Defender capsule", + "href": "/Defender_capsule", + "image": "/images/thumb/Defender_capsule.png/32px-Defender_capsule.png" + }, + { + "name": "Distractor capsule", + "href": "/Distractor_capsule", + "image": "/images/thumb/Distractor_capsule.png/32px-Distractor_capsule.png" + }, + { + "name": "Destroyer capsule", + "href": "/Destroyer_capsule", + "image": "/images/thumb/Destroyer_capsule.png/32px-Destroyer_capsule.png" + }, + { + "name": "Light armor", + "href": "/Light_armor", + "image": "/images/thumb/Light_armor.png/32px-Light_armor.png" + }, + { + "name": "Heavy armor", + "href": "/Heavy_armor", + "image": "/images/thumb/Heavy_armor.png/32px-Heavy_armor.png" + }, + { + "name": "Modular armor", + "href": "/Modular_armor", + "image": "/images/thumb/Modular_armor.png/32px-Modular_armor.png" + }, + { + "name": "Power armor", + "href": "/Power_armor", + "image": "/images/thumb/Power_armor.png/32px-Power_armor.png" + }, + { + "name": "Power armor MK2", + "href": "/Power_armor_MK2", + "image": "/images/thumb/Power_armor_MK2.png/32px-Power_armor_MK2.png" + }, + { + "name": "Portable solar panel", + "href": "/Portable_solar_panel", + "image": "/images/thumb/Portable_solar_panel.png/32px-Portable_solar_panel.png" + }, + { + "name": "Portable fusion reactor", + "href": "/Portable_fusion_reactor", + "image": "/images/thumb/Portable_fusion_reactor.png/32px-Portable_fusion_reactor.png" + }, + { + "name": "Personal battery", + "href": "/Personal_battery", + "image": "/images/thumb/Personal_battery.png/32px-Personal_battery.png" + }, + { + "name": "Personal battery MK2", + "href": "/Personal_battery_MK2", + "image": "/images/thumb/Personal_battery_MK2.png/32px-Personal_battery_MK2.png" + }, + { + "name": "Belt immunity equipment", + "href": "/Belt_immunity_equipment", + "image": "/images/thumb/Belt_immunity_equipment.png/32px-Belt_immunity_equipment.png" + }, + { + "name": "Exoskeleton", + "href": "/Exoskeleton", + "image": "/images/thumb/Exoskeleton.png/32px-Exoskeleton.png" + }, + { + "name": "Personal roboport", + "href": "/Personal_roboport", + "image": "/images/thumb/Personal_roboport.png/32px-Personal_roboport.png" + }, + { + "name": "Personal roboport MK2", + "href": "/Personal_roboport_MK2", + "image": "/images/thumb/Personal_roboport_MK2.png/32px-Personal_roboport_MK2.png" + }, + { + "name": "Nightvision", + "href": "/Nightvision", + "image": "/images/thumb/Nightvision.png/32px-Nightvision.png" + }, + { + "name": "Energy shield", + "href": "/Energy_shield", + "image": "/images/thumb/Energy_shield.png/32px-Energy_shield.png" + }, + { + "name": "Energy shield MK2", + "href": "/Energy_shield_MK2", + "image": "/images/thumb/Energy_shield_MK2.png/32px-Energy_shield_MK2.png" + }, + { + "name": "Personal laser defense", + "href": "/Personal_laser_defense", + "image": "/images/thumb/Personal_laser_defense.png/32px-Personal_laser_defense.png" + }, + { + "name": "Discharge defense", + "href": "/Discharge_defense", + "image": "/images/thumb/Discharge_defense.png/32px-Discharge_defense.png" + }, + { + "name": "Discharge defense remote", + "href": "/Discharge_defense_remote", + "image": "/images/thumb/Discharge_defense_remote.png/32px-Discharge_defense_remote.png" + }, + { "name": "Wall", "href": "/Wall", "image": "/images/thumb/Wall.png/32px-Wall.png" }, + { "name": "Gate", "href": "/Gate", "image": "/images/thumb/Gate.png/32px-Gate.png" }, + { + "name": "Gun turret", + "href": "/Gun_turret", + "image": "/images/thumb/Gun_turret.png/32px-Gun_turret.png" + }, + { + "name": "Laser turret", + "href": "/Laser_turret", + "image": "/images/thumb/Laser_turret.png/32px-Laser_turret.png" + }, + { + "name": "Flamethrower turret", + "href": "/Flamethrower_turret", + "image": "/images/thumb/Flamethrower_turret.png/32px-Flamethrower_turret.png" + }, + { + "name": "Artillery turret", + "href": "/Artillery_turret", + "image": "/images/thumb/Artillery_turret.png/32px-Artillery_turret.png" + }, + { + "name": "Artillery targeting remote", + "href": "/Artillery_targeting_remote", + "image": "/images/thumb/Artillery_targeting_remote.png/32px-Artillery_targeting_remote.png" + }, + { "name": "Radar", "href": "/Radar", "image": "/images/thumb/Radar.png/32px-Radar.png" } +] diff --git a/src/calculateInputs.ts b/src/calculateInputs.ts index 104c85b..dad14fc 100644 --- a/src/calculateInputs.ts +++ b/src/calculateInputs.ts @@ -1,20 +1,24 @@ -import {EnrichedEntity} from "./types"; +import { EnrichedEntity } from './types' -export const calculateInputs = (allProducingFactories: string[], ignoredFactories: string[], baseFactories: string[], exportedFactories: Set, findFactory: (uid: string) => EnrichedEntity|undefined) => { - const prducingSet = new Set(allProducingFactories) - const ignored = new Set(ignoredFactories) +export const calculateInputs = ( + allProducingFactories: string[], + baseFactories: string[], + exportedFactories: Set, + findFactory: (uid: string) => EnrichedEntity | undefined +) => { + const producingSet = new Set(allProducingFactories) const base = new Set(baseFactories) const inputs = new Set() const intermediates = new Set() - let next: string|undefined - while (next = allProducingFactories.pop()) { + let next: string | undefined + while ((next = allProducingFactories.pop())) { const pres = Object.keys(findFactory(next)?.recipe?.prerequisites ?? {}) for (const pre of pres) { if (exportedFactories.has(pre) || base.has(pre)) { - if (!prducingSet.has(pre)) inputs.add(pre) + if (!producingSet.has(pre)) inputs.add(pre) } else if (!intermediates.has(pre)) { - if (!prducingSet.has(pre)) intermediates.add(pre) + if (!producingSet.has(pre)) intermediates.add(pre) allProducingFactories.push(pre) } } diff --git a/src/database/groups.ts b/src/database/groups.ts index 86ba3d3..1d93c11 100644 --- a/src/database/groups.ts +++ b/src/database/groups.ts @@ -1,22 +1,22 @@ -import {database} from "./start"; -import {Dict, Group} from "../types"; -import {Filter, ObjectId} from "mongodb"; +import { database } from './start' +import { Dict, Group } from '../types' +import { Filter, ObjectId } from 'mongodb' export interface GroupData { - groups: Dict, - ignored: string[], + groups: Dict + ignored: string[] base: string[] } export type InsertMeta = T & { - createdOn: Date, - modifiedOn: Date, + createdOn: Date + modifiedOn: Date accessedOn: Date } type GroupFilter = Filter> -export async function setGroups(data: GroupData): Promise { +export async function setGroups(data: GroupData): Promise { const collection = (await database.resolve())?.collection('setups') if (!collection) return const result = await collection.insertOne({ @@ -25,7 +25,6 @@ export async function setGroups(data: GroupData): Promise { modifiedOn: new Date(), accessedOn: new Date() }) - console.log(result.insertedId, result.insertedId.toString()) return result.insertedId.toString() } @@ -35,38 +34,48 @@ function getUuid(uuid: string): GroupFilter { } } -export async function setFactories(uuid: string, type: 'ignored'|'base', factories: string[]): Promise { +export async function setFactories( + uuid: string, + type: 'ignored' | 'base', + factories: string[] +): Promise { const collection = (await database.resolve())?.collection('setups') if (!collection) return false - collection.updateOne(getUuid(uuid), {$set: {[type]: factories} as never}) + collection.updateOne(getUuid(uuid), { $set: { [type]: factories } as never }) return true } - export async function getGroup(uuid: string) { const collection = (await database.resolve())?.collection('setups') if (!collection) return const data = (await collection.findOne(getUuid(uuid))) ?? undefined if (data) { - await collection.updateOne(getUuid(uuid), { $set: {accessedOn: new Date()}}) + await collection.updateOne(getUuid(uuid), { $set: { accessedOn: new Date() } }) } return data } -export async function renameGroup(uuid: string, oldName: string, newName: string): Promise { +export async function renameGroup( + uuid: string, + oldName: string, + newName: string +): Promise { oldName = oldName.replace(/[.$]/g, '') newName = newName.replace(/[.$]/g, '') const data = await getGroup(uuid) if (data?.groups && !(newName in data.groups)) { const collection = (await database.resolve())?.collection('setups') - console.log("fere", `groups.${oldName}`, `groups.${newName}`) if (!collection) return false - await collection.updateOne(getUuid(uuid), { $set: { + await collection.updateOne(getUuid(uuid), { + $set: { [`groups.${oldName}.name`]: newName - } as never}) - await collection.updateOne(getUuid(uuid), { $rename: { + } as never + }) + await collection.updateOne(getUuid(uuid), { + $rename: { [`groups.${oldName}`]: `groups.${newName}` - }}) + } + }) return true } return false @@ -78,7 +87,9 @@ export async function addGroup(uuid: string, name: string): Promise { if (data?.groups && !(name in data.groups)) { const collection = (await database.resolve())?.collection('setups') if (!collection) return false - await collection.updateOne(getUuid(uuid), {$set: {[`groups.${name}`]: {name, exports: [], malls: []} as never}}) + await collection.updateOne(getUuid(uuid), { + $set: { [`groups.${name}`]: { name, exports: [], malls: [] } as never } + }) return true } return false @@ -90,20 +101,26 @@ export async function removeGroup(uuid: string, name: string): Promise if (data?.groups && name in data.groups) { const collection = (await database.resolve())?.collection('setups') if (!collection) return false - console.log(`groups.${name}`) - await collection.updateOne(getUuid(uuid), {$unset: {[`groups.${name}`]: ""}}) + await collection.updateOne(getUuid(uuid), { $unset: { [`groups.${name}`]: '' } }) return true } return false } -export async function setFactoriesOfGroup(uuid: string, name: string, type: 'exports'|'malls', factories: string[]): Promise { +export async function setFactoriesOfGroup( + uuid: string, + name: string, + type: 'exports' | 'malls', + factories: string[] +): Promise { name = name.replace(/[.$]/g, '') const data = await getGroup(uuid) - if (data?.groups && (name in data.groups)) { + if (data?.groups && name in data.groups) { const collection = (await database.resolve())?.collection('setups') if (!collection) return false - await collection.updateOne(getUuid(uuid), {$set: {[`groups.${name}.${type}`]: factories} as never}) + await collection.updateOne(getUuid(uuid), { + $set: { [`groups.${name}.${type}`]: factories } as never + }) return true } return false diff --git a/src/database/start.ts b/src/database/start.ts index 34ef8d2..058e621 100644 --- a/src/database/start.ts +++ b/src/database/start.ts @@ -1,23 +1,21 @@ -import {Collection, Db, MongoClient} from 'mongodb' +import { Collection, Db, MongoClient } from 'mongodb' import getConfig from 'next/config' -import {Resolvable} from "../utils/Resolvable"; -import {GroupData, InsertMeta} from "./groups"; +import { Resolvable } from '../utils/Resolvable' +import { GroupData, InsertMeta } from './groups' +import { logger } from '../utils/logger' -const { serverRuntimeConfig: { - MONGO_URL, - MONGO_USER, - MONGO_PASS, - MONGO_DB -} } = getConfig() +const { + serverRuntimeConfig: { MONGO_URL, MONGO_USER, MONGO_PASS, MONGO_DB } +} = getConfig() async function getDatabase() { - const url = `mongodb://${MONGO_USER ? `${MONGO_USER}:${MONGO_PASS ?? ''}@` : ''}${MONGO_URL}`; - const client = new MongoClient(url); - await client.connect(); - console.log('Connected successfully to server') - return client.db(MONGO_DB) as unknown as (Omit & { - collection : (_: 'setups') => Collection> - }) + const url = `mongodb://${MONGO_USER ? `${MONGO_USER}:${MONGO_PASS ?? ''}@` : ''}${MONGO_URL}` + const client = new MongoClient(url) + await client.connect() + logger.info('Connected successfully to server') + return client.db(MONGO_DB) as unknown as Omit & { + collection: (_: 'setups') => Collection> + } } export const database = new Resolvable(getDatabase) diff --git a/src/download.ts b/src/download.ts index 0fd4490..37eb626 100644 --- a/src/download.ts +++ b/src/download.ts @@ -1,29 +1,30 @@ export function download(filename: string, data: Uint8Array) { - const tag = document.createElement("a"); - tag.style.display = "none"; - document.body.appendChild(tag); - const blob = new Blob([data], {type: "octet/stream"}), - url = window.URL.createObjectURL(blob); - tag.href = url; - tag.download = filename; - tag.click(); - window.URL.revokeObjectURL(url); - document.body.removeChild(tag); + const tag = document.createElement('a') + tag.style.display = 'none' + document.body.appendChild(tag) + const blob = new Blob([data], { type: 'octet/stream' }), + url = window.URL.createObjectURL(blob) + tag.href = url + tag.download = filename + tag.click() + window.URL.revokeObjectURL(url) + document.body.removeChild(tag) } export async function streamToArrayBuffer(stream: ReadableStream): Promise { - let result = new Uint8Array(0); - const reader = stream.getReader(); - while (true) { // eslint-disable-line no-constant-condition - const { done, value } = await reader.read(); + let result = new Uint8Array(0) + const reader = stream.getReader() + while (true) { + // eslint-disable-line no-constant-condition + const { done, value } = await reader.read() if (done) { - break; + break } - const newResult = new Uint8Array(result.length + value.length); - newResult.set(result); - newResult.set(value, result.length); + const newResult = new Uint8Array(result.length + value.length) + newResult.set(result) + newResult.set(value, result.length) result = newResult } - return result; + return result } diff --git a/src/getServerSideProps.ts b/src/getServerSideProps.ts index 168de77..88f2879 100644 --- a/src/getServerSideProps.ts +++ b/src/getServerSideProps.ts @@ -1,6 +1,6 @@ -import {GetServerSideProps} from "next"; -import {getGroup, setGroups} from "./database/groups"; -import {Dict, Group} from "./types"; +import { GetServerSideProps } from 'next' +import { getGroup, setGroups } from './database/groups' +import { Dict, Group } from './types' export interface PropsGroupProvider { id: string @@ -9,9 +9,11 @@ export interface PropsGroupProvider { base: string[] } -export const getServerSidePropsGroupProvider: GetServerSideProps = async ({query}) => { +export const getServerSidePropsGroupProvider: GetServerSideProps = async ({ + query +}) => { const id = Array.isArray(query?.id) ? query.id[0] : query?.id - const data = id && await getGroup(id) + const data = id && (await getGroup(id)) if (data) { return { props: { @@ -22,15 +24,14 @@ export const getServerSidePropsGroupProvider: GetServerSideProps>(node: GraphNode, nodeUid: () => string): GraphNodeWithIds { +function generateIds>( + node: GraphNode, + nodeUid: () => string +): GraphNodeWithIds { return { ...node, - ___uid: `${node.name.replace(/[^a-z]/gi, '').toLowerCase().substring(0, 3)}_${nodeUid()}`, + ___uid: `${node.name + .replace(/[^a-z]/gi, '') + .toLowerCase() + .substring(0, 3)}_${nodeUid()}`, ___uidInputs: [], ___uidOutputs: [] } } -function generateAdditional>(uid: string, type: 'i'|'h'|'o', nodeUid: () => string): GraphNodeWithIds { +function generateAdditional( + uid: string, + type: 'i' | 'h' | 'o', + nodeUid: () => string +): GraphNodeWithIds { return { inputs: type !== 'i' ? [uid] : [], outputs: type !== 'o' ? [uid] : [], name: uid, ___type: type, - ___uid: `${uid.replace(/[^a-z]/gi, '').toLowerCase().substring(0, 3)}_${nodeUid()}_${type}`, + ___uid: `${uid + .replace(/[^a-z]/gi, '') + .toLowerCase() + .substring(0, 3)}_${nodeUid()}_${type}`, ___uidInputs: [], ___uidOutputs: [] } } -function splitIntoRows>(inputs: string[], nodes: GraphNode[], nodeUid: () => string): [string[][], Dict>] { +function splitIntoRows>( + inputs: string[], + nodes: GraphNode[], + nodeUid: () => string +): [string[][], Dict>] { const nodesWithId: Dict> = {} const available = new Set(inputs) let queue = [...nodes] @@ -35,7 +52,7 @@ function splitIntoRows>(inputs: string[], nodes: GraphNo const availableOfRow: string[] = [] rows.push([]) - queue = queue.filter((node) => { + queue = queue.filter(node => { const isPlaceable = node.inputs.every(input => available.has(input)) if (isPlaceable) { const nodeWithId: GraphNodeWithIds = generateIds(node, nodeUid) @@ -48,7 +65,7 @@ function splitIntoRows>(inputs: string[], nodes: GraphNo availableOfRow.map(uid => available.add(uid)) if (amount === queue.length) { - console.warn("Loop detected! Left over:", queue) + console.warn('Loop detected! Left over:', queue) rows.pop() break } @@ -56,78 +73,123 @@ function splitIntoRows>(inputs: string[], nodes: GraphNo return [rows, nodesWithId] } -function addAdditionalNodes>(rowsRaw: string[][], nodesRaw: Dict>, inputs: string[], outputs: string[], nodeUid: () => string): [string[][], Dict>] { +function addAdditionalNodes>( + rowsRaw: string[][], + nodesRaw: Dict>, + inputs: string[], + outputs: string[], + nodeUid: () => string +): [string[][], Dict>] { const addedInputs: Dict = {} const res: string[][] = deepcopy([[], ...rowsRaw, []]) - const resNodes: Dict> = deepcopy(nodesRaw) + const resNodes: Dict> = deepcopy(nodesRaw) for (let i = 0; i < rowsRaw.length; i++) { const rowInputs = uniquify(rowsRaw[i].flatMap(row => resNodes[row].inputs)) - for (let rowInput of rowInputs) { + for (const rowInput of rowInputs) { if (rowInput in addedInputs) { - for (let j = addedInputs[rowInput]+1; j < i+1; j++) { - const nodeWithId: GraphNodeWithIds = generateAdditional(rowInput, 'h', nodeUid) + for (let j = addedInputs[rowInput] + 1; j < i + 1; j++) { + const nodeWithId: GraphNodeWithIds = generateAdditional( + rowInput, + 'h', + nodeUid + ) res[j].push(nodeWithId.___uid) resNodes[nodeWithId.___uid] = nodeWithId } addedInputs[rowInput] = i } else if (inputs.includes(rowInput)) { - const nodeWithId: GraphNodeWithIds = generateAdditional(rowInput, 'i', nodeUid) + const nodeWithId: GraphNodeWithIds = generateAdditional( + rowInput, + 'i', + nodeUid + ) res[i].push(nodeWithId.___uid) resNodes[nodeWithId.___uid] = nodeWithId addedInputs[rowInput] = i } } const rowOutputs = uniquify(rowsRaw[i].flatMap(row => resNodes[row].outputs)) - for (let rowOutput of rowOutputs) { + for (const rowOutput of rowOutputs) { if (outputs?.includes(rowOutput)) { - const nodeWithId: GraphNodeWithIds = generateAdditional(rowOutput, 'o', nodeUid) - res[i+2].push(nodeWithId.___uid) + const nodeWithId: GraphNodeWithIds = generateAdditional( + rowOutput, + 'o', + nodeUid + ) + res[i + 2].push(nodeWithId.___uid) resNodes[nodeWithId.___uid] = nodeWithId } - addedInputs[rowOutput] = i+1 + addedInputs[rowOutput] = i + 1 } } - if (res[res.length-1].length === 0) res.splice(res.length-1, 1) + if (res[res.length - 1].length === 0) res.splice(res.length - 1, 1) return [res, resNodes] } -function linkNodes>(rowsWithInOut: string[][], nodesWithInOut: Dict>): Dict> { - type Store = {input: Dict[], output: Dict[]} +function linkNodes>( + rowsWithInOut: string[][], + nodesWithInOut: Dict> +): Dict> { + type Store = { input: Dict[], output: Dict[] } const store: Store = { input: Array.from(rowsWithInOut, Object), output: Array.from(rowsWithInOut, Object) } - const nodesPremapping = (node: GraphNodeWithIds, rowIdx: number) => { - node.inputs.forEach(input => store.input[rowIdx][input] = [...(store.input[rowIdx][input] ?? []), node.___uid]) - node.outputs.forEach(output => store.output[rowIdx][output] = [...(store.output[rowIdx][output] ?? []), node.___uid]) - }; - const linkInOut = (node: GraphNodeWithIds, rowIdx: number) => { + const nodesPremapping = (node: GraphNodeWithIds, rowIdx: number) => { + node.inputs.forEach( + input => (store.input[rowIdx][input] = [...(store.input[rowIdx][input] ?? []), node.___uid]) + ) + node.outputs.forEach( + output => + (store.output[rowIdx][output] = [...(store.output[rowIdx][output] ?? []), node.___uid]) + ) + } + const linkInOut = (node: GraphNodeWithIds, rowIdx: number) => { if (rowIdx > 0) - node.___uidInputs = uniquify(node.inputs.flatMap(input => store.output[rowIdx - 1][input]).filter(isNonNullable)) - if (rowIdx < rowsWithInOut.length-1) - node.___uidOutputs = uniquify(node.outputs.flatMap(output => store.input[rowIdx + 1][output]).filter(isNonNullable)) - }; + node.___uidInputs = uniquify( + node.inputs.flatMap(input => store.output[rowIdx - 1][input]).filter(isNonNullable) + ) + if (rowIdx < rowsWithInOut.length - 1) + node.___uidOutputs = uniquify( + node.outputs.flatMap(output => store.input[rowIdx + 1][output]).filter(isNonNullable) + ) + } - rowsWithInOut.forEach((row, rowIdx) => row.forEach(uid => nodesPremapping(nodesWithInOut[uid], rowIdx))) + rowsWithInOut.forEach((row, rowIdx) => + row.forEach(uid => nodesPremapping(nodesWithInOut[uid], rowIdx)) + ) rowsWithInOut.forEach((row, rowIdx) => row.forEach(uid => linkInOut(nodesWithInOut[uid], rowIdx))) return nodesWithInOut } -function crossingsOf>(fixed: string[], flex: string[], nodes: Dict>, isDown: boolean): [number[][], number] { +function crossingsOf>( + fixed: string[], + flex: string[], + nodes: Dict>, + isDown: boolean +): [number[][], number] { const result = Array.from(flex, () => Array.from(flex, () => 9999999)) let score = 0 - for (let i = 0; i < flex.length-1; i++) { - for (let j = i+1; j < flex.length; j++) { + for (let i = 0; i < flex.length - 1; i++) { + for (let j = i + 1; j < flex.length; j++) { const inputsI = new Set(nodes[flex[i]][isDown ? '___uidInputs' : '___uidOutputs']) const inputsJ = new Set(nodes[flex[j]][isDown ? '___uidInputs' : '___uidOutputs']) - const diff = fixed.reduce(([size, acc], curr) => { - inputsI.has(curr) && size-- - return [size, acc + (inputsJ.has(curr) ? size : 0)] - }, [inputsI.size, 0])[1] - fixed.reduce(([size, acc], curr) => { - inputsJ.has(curr) && size-- - return [size, acc + (inputsI.has(curr) ? size : 0)] - }, [inputsJ.size, 0])[1] + const diff = + fixed.reduce( + ([size, acc], curr) => { + inputsI.has(curr) && size-- + return [size, acc + (inputsJ.has(curr) ? size : 0)] + }, + [inputsI.size, 0] + )[1] - + fixed.reduce( + ([size, acc], curr) => { + inputsJ.has(curr) && size-- + return [size, acc + (inputsI.has(curr) ? size : 0)] + }, + [inputsJ.size, 0] + )[1] result[i][j] = diff result[j][i] = -diff score += diff @@ -136,82 +198,102 @@ function crossingsOf>(fixed: string[], flex: string[], n return [result, score] } -function optimizeOrder>(rowsWithInOut: string[][], nodesWithInOut: Dict>): [string[][], number] { - - function addCosts(costsUp: [number[][], number], costsDown: [number[][], number]): [number[][], number] { +function optimizeOrder>( + rowsWithInOut: string[][], + nodesWithInOut: Dict> +): [string[][], number] { + function addCosts( + costsUp: [number[][], number], + costsDown: [number[][], number] + ): [number[][], number] { return [ - costsUp[0].map((row, rowIdx) => row.map((col, colIdx) => col+costsDown[0][rowIdx][colIdx])), + costsUp[0].map((row, rowIdx) => row.map((col, colIdx) => col + costsDown[0][rowIdx][colIdx])), costsUp[1] + costsDown[1] ] } - function improveRow(top: string[]|undefined, mid: string[], bot: string[]|undefined) { + function improveRow(top: string[] | undefined, mid: string[], bot: string[] | undefined) { const costsUp = top ? crossingsOf(top, mid, nodesWithInOut, true) : undefined const costsDown = bot ? crossingsOf(bot, mid, nodesWithInOut, false) : undefined - const [costs, scoreConst] = costsUp && costsDown ? addCosts(costsUp, costsDown) : costsDown ?? costsUp ?? [undefined, 0] + const [costs, scoreConst] = + costsUp && costsDown ? addCosts(costsUp, costsDown) : costsDown ?? costsUp ?? [undefined, 0] let score = scoreConst if (!costs) return score let improvementInRow = true while (improvementInRow) { improvementInRow = false const colBest = costs - .map((_, idx) => costs - .slice(0, idx) - .map(r => r[idx]) - .reverse() - .reduce(([sum, best], curr, i) => { - return sum + curr > best.sum - ? [sum + curr, {sum: sum+curr, move: -i-1, idx}] as const - : [sum + curr, best] as const - }, [0, {sum: -10000, move: 0, idx: 0}] as readonly [number, Reduce])[1] + .map( + (_, idx) => + costs + .slice(0, idx) + .map(r => r[idx]) + .reverse() + .reduce( + ([sum, best], curr, i) => { + return sum + curr > best.sum + ? ([sum + curr, { sum: sum + curr, move: -i - 1, idx }] as const) + : ([sum + curr, best] as const) + }, + [0, { sum: -10000, move: 0, idx: 0 }] as readonly [number, Reduce] + )[1] ) .filter(isNonNullable) const rowBest = costs - .map((_, idx) => costs[idx] - .slice(idx+1) - .reduce(([sum, best], curr, i) => { - return sum + curr > best.sum - ? [sum + curr, {sum: sum+curr, move: i+1, idx}] as const - : [sum + curr, best] as const - }, [0, {sum: -10000, move: 0, idx: 0}] as readonly [number, Reduce])[1] + .map( + (_, idx) => + costs[idx].slice(idx + 1).reduce( + ([sum, best], curr, i) => { + return sum + curr > best.sum + ? ([sum + curr, { sum: sum + curr, move: i + 1, idx }] as const) + : ([sum + curr, best] as const) + }, + [0, { sum: -10000, move: 0, idx: 0 }] as readonly [number, Reduce] + )[1] ) .filter(isNonNullable) const replacement = [...colBest, ...rowBest].sort(sortByProperty(red => -red.sum))[0] if (replacement.sum > 0) { - score -= 2*replacement.sum + score -= 2 * replacement.sum improvement = true improvementInRow = true - costs.splice(replacement.move+replacement.idx, 0, ...costs.splice(replacement.idx, 1)) - costs.map(col => col.splice(replacement.move+replacement.idx, 0, ...col.splice(replacement.idx, 1))) - mid.splice(replacement.move+replacement.idx, 0, ...mid.splice(replacement.idx, 1)) + costs.splice(replacement.move + replacement.idx, 0, ...costs.splice(replacement.idx, 1)) + costs.map(col => + col.splice(replacement.move + replacement.idx, 0, ...col.splice(replacement.idx, 1)) + ) + mid.splice(replacement.move + replacement.idx, 0, ...mid.splice(replacement.idx, 1)) } } return score } - type Reduce = {sum: number, move: number, idx: number} + type Reduce = { sum: number, move: number, idx: number } let improvement = true - let scores: number[] = [] + const scores: number[] = [] while (improvement) { improvement = false rowsWithInOut.reduce((top, mid, idx) => { - scores[idx] = improveRow(top, mid, rowsWithInOut[idx+1]) + scores[idx] = improveRow(top, mid, rowsWithInOut[idx + 1]) return mid - }, undefined as string[]|undefined) + }, undefined as string[] | undefined) rowsWithInOut.reduceRight((bot, mid, idx) => { - scores[idx] = improveRow(rowsWithInOut[idx-1], mid, bot) + scores[idx] = improveRow(rowsWithInOut[idx - 1], mid, bot) return mid - }, undefined as string[]|undefined) + }, undefined as string[] | undefined) } - return [rowsWithInOut, scores.reduce((a, b) => a+b)] + return [rowsWithInOut, scores.reduce((a, b) => a + b)] } -export function findBest>(rowsWithInOut: string[][], nodesWithInOut: Dict>, timeLimit: number) { +export function findBest>( + rowsWithInOut: string[][], + nodesWithInOut: Dict>, + timeLimit: number +) { let bestScore = Infinity let bestRows = deepcopy(rowsWithInOut) - let limit = Date.now() + timeLimit + const limit = Date.now() + timeLimit let iterSinceImprovements = 0 - let rng = seedrandom.alea("We are SEEED, ya!") + const rng = seedrandom.alea('We are SEEED, ya!') while (true) { if (Date.now() > limit) break if (iterSinceImprovements > 100) break @@ -223,21 +305,31 @@ export function findBest>(rowsWithInOut: string[][], nod } else { iterSinceImprovements++ } - rowsOptimized.forEach((row, ) => shuffleInplace(row, rng)) + rowsOptimized.forEach(row => shuffleInplace(row, rng)) } - console.log(bestScore) return bestRows } -export function graphUntangled>(nodes: GraphNode[], inputs: string[], outputs: string[], timeLimit = 0): [string[][], Dict>] { - const nodeSeed = seedrandom.alea("node") +export function graphUntangled>( + nodes: GraphNode[], + inputs: string[], + outputs: string[], + timeLimit = 0 +): [string[][], Dict>] { + const nodeSeed = seedrandom.alea('node') const nodeUid = () => Math.abs(nodeSeed.int32()).toString(16).substring(0, 3) //console.log('---------------') const [rowsRaw, nodesRaw] = splitIntoRows(inputs, nodes, nodeUid) //console.log("Step 1") //console.table(rowsRaw) //console.table(nodesRaw) - const [rowsWithInOut, nodesWithInOut] = addAdditionalNodes(rowsRaw, nodesRaw, inputs, outputs, nodeUid) + const [rowsWithInOut, nodesWithInOut] = addAdditionalNodes( + rowsRaw, + nodesRaw, + inputs, + outputs, + nodeUid + ) //console.log("Step 2") //console.table(rowsWithInOut) //console.table(nodesWithInOut) diff --git a/src/graph-untangle/types.ts b/src/graph-untangle/types.ts index 98b1042..214ea77 100644 --- a/src/graph-untangle/types.ts +++ b/src/graph-untangle/types.ts @@ -1,4 +1,4 @@ -import {Dict} from "../types"; +import { Dict } from '../types' interface GraphNodeBase { inputs: string[] @@ -14,7 +14,8 @@ export type GraphNodeWithIds> = GraphNode & { } export type AdditionalNode = { - ___type: 'i'|'h'|'o' + ___type: 'i' | 'h' | 'o' } -export const isAdditionalNode = (node: unknown): node is GraphNodeWithIds => !!(node && typeof node === 'object' && '___type' in node) +export const isAdditionalNode = (node: unknown): node is GraphNodeWithIds => + !!(node && typeof node === 'object' && '___type' in node) diff --git a/src/hooks/useEventListener.ts b/src/hooks/useEventListener.ts index 7374839..c0a57db 100644 --- a/src/hooks/useEventListener.ts +++ b/src/hooks/useEventListener.ts @@ -8,18 +8,18 @@ export function useEventListener( eventName: K, handler: (event: WindowEventMap[K]) => void, element?: undefined, - options?: boolean | AddEventListenerOptions, + options?: boolean | AddEventListenerOptions ): void // Element Event based useEventListener interface export function useEventListener< K extends keyof HTMLElementEventMap, - T extends HTMLElement = HTMLDivElement, - >( + T extends HTMLElement = HTMLDivElement +>( eventName: K, handler: (event: HTMLElementEventMap[K]) => void, element: RefObject, - options?: boolean | AddEventListenerOptions, + options?: boolean | AddEventListenerOptions ): void // Document Event based useEventListener interface @@ -27,20 +27,18 @@ export function useEventListener( eventName: K, handler: (event: DocumentEventMap[K]) => void, element: RefObject, - options?: boolean | AddEventListenerOptions, + options?: boolean | AddEventListenerOptions ): void export function useEventListener< KW extends keyof WindowEventMap, KH extends keyof HTMLElementEventMap, - T extends HTMLElement | void = void, - >( + T extends HTMLElement | void = void +>( eventName: KW | KH, - handler: ( - event: WindowEventMap[KW] | HTMLElementEventMap[KH] | Event, - ) => void, + handler: (event: WindowEventMap[KW] | HTMLElementEventMap[KH] | Event) => void, element?: RefObject, - options?: boolean | AddEventListenerOptions, + options?: boolean | AddEventListenerOptions ) { // Create a ref that stores handler const savedHandler = useRef(handler) diff --git a/src/hooks/useFactories.ts b/src/hooks/useFactories.ts index b240497..d518a2b 100644 --- a/src/hooks/useFactories.ts +++ b/src/hooks/useFactories.ts @@ -1,23 +1,23 @@ -import {EnrichedEntity, Entity} from "../types"; -import details from "../../res/details.json"; -import manual from "../../res/manual.json"; +import { EnrichedEntity, Entity } from '../types' +import details from '../../res/details.json' +import manual from '../../res/manual.json' const joined = [...details, ...manual] as Entity[] const factories = joined.map((detail: EnrichedEntity) => { - detail.usedBy = joined - .filter(f => Object - .keys(f.recipe?.prerequisites ?? {}) - .includes(detail.href) - ) - return detail; + detail.usedBy = joined.filter(f => + Object.keys(f.recipe?.prerequisites ?? {}).includes(detail.href) + ) + return detail }) -const detailsMap = Object.fromEntries(factories.map((detail: EnrichedEntity) => [detail.href, detail])) +const detailsMap = Object.fromEntries( + factories.map((detail: EnrichedEntity) => [detail.href, detail]) +) export const useFactories = () => ({ factories, - findFactory: (uid: string): EnrichedEntity|undefined => { + findFactory: (uid: string): EnrichedEntity | undefined => { return detailsMap[uid] } }) diff --git a/src/hooks/useIsomorphicLayoutEffect.ts b/src/hooks/useIsomorphicLayoutEffect.ts index 49ca31f..5d7dc3c 100644 --- a/src/hooks/useIsomorphicLayoutEffect.ts +++ b/src/hooks/useIsomorphicLayoutEffect.ts @@ -1,4 +1,3 @@ import { useEffect, useLayoutEffect } from 'react' -export const useIsomorphicLayoutEffect = - typeof window !== 'undefined' ? useLayoutEffect : useEffect +export const useIsomorphicLayoutEffect = typeof window !== 'undefined' ? useLayoutEffect : useEffect diff --git a/src/hooks/useLocalStorage.ts b/src/hooks/useLocalStorage.ts index bdef419..8f1c681 100644 --- a/src/hooks/useLocalStorage.ts +++ b/src/hooks/useLocalStorage.ts @@ -1,10 +1,4 @@ -import { - Dispatch, - SetStateAction, - useCallback, - useEffect, - useState, -} from 'react' +import { Dispatch, SetStateAction, useCallback, useEffect, useState } from 'react' // See: https://usehooks-ts.com/react-hook/use-event-listener import { useEventListener } from './useEventListener' @@ -41,30 +35,33 @@ export function useLocalStorage(key: string, initialValue: T): [T, SetValue = useCallback(value => { - // Prevent build error "window is undefined" but keeps working - if (typeof window == 'undefined') { - console.warn( - `Tried setting localStorage key “${key}” even though environment is not a client`, - ) - } + const setValue: SetValue = useCallback( + value => { + // Prevent build error "window is undefined" but keeps working + if (typeof window == 'undefined') { + console.warn( + `Tried setting localStorage key “${key}” even though environment is not a client` + ) + } - try { - // Allow value to be a function so we have the same API as useState - const newValue = value instanceof Function ? value(storedValue) : value + try { + // Allow value to be a function so we have the same API as useState + const newValue = value instanceof Function ? value(storedValue) : value - // Save to local storage - window.localStorage.setItem(key, JSON.stringify(newValue)) + // Save to local storage + window.localStorage.setItem(key, JSON.stringify(newValue)) - // Save state - setStoredValue(newValue) + // Save state + setStoredValue(newValue) - // We dispatch a custom event so every useLocalStorage hook are notified - window.dispatchEvent(new Event('local-storage')) - } catch (error) { - console.warn(`Error setting localStorage key “${key}”:`, error) - } - }, [key, storedValue]) + // We dispatch a custom event so every useLocalStorage hook are notified + window.dispatchEvent(new Event('local-storage')) + } catch (error) { + console.warn(`Error setting localStorage key “${key}”:`, error) + } + }, + [key, storedValue] + ) useEffect(() => { setStoredValue(readValue()) @@ -78,7 +75,7 @@ export function useLocalStorage(key: string, initialValue: T): [T, SetValue { - serverRuntimeConfig: ServerRuntimeConfig, + serverRuntimeConfig: ServerRuntimeConfig publicRuntimeConfig: PublicRuntimeConfig } export default getConfig diff --git a/src/svg.ts b/src/svg.ts index e4f0185..813fc81 100644 --- a/src/svg.ts +++ b/src/svg.ts @@ -1,14 +1,14 @@ export function createPath(container: DOMRect, start: DOMRect, end: DOMRect) { - const startX = Math.round(start.x + start.width/2 - container.x) + const startX = Math.round(start.x + start.width / 2 - container.x) const startY = Math.round(start.bottom - container.y) - const endX = Math.round(end.x + end.width/2 - container.x) + const endX = Math.round(end.x + end.width / 2 - container.x) const endY = Math.round(end.top - container.y) const mid = Math.round((start.bottom + end.top) / 2 - container.y) return `M${startX},${startY} C${startX},${mid} ${endX},${mid} ${endX},${endY}` } export function drawLine(container: DOMRect, elem: DOMRect) { - const x = Math.round(elem.x + elem.width/2 - container.x) + const x = Math.round(elem.x + elem.width / 2 - container.x) const top = Math.round(elem.top - container.y) const bottom = Math.round(elem.bottom - container.y) return `M${x},${top} L${x},${bottom}` diff --git a/src/types/FrontendApi.ts b/src/types/FrontendApi.ts index 3395217..0eeb517 100644 --- a/src/types/FrontendApi.ts +++ b/src/types/FrontendApi.ts @@ -1,4 +1,4 @@ -import {ValidationError} from "jsonschema"; +import { ValidationError } from 'jsonschema' export interface ErrorMessage { message: string // Human readable error message diff --git a/src/utils.ts b/src/utils.ts index 8131368..3ab953c 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,5 +1,5 @@ -import {Dict} from "./types"; -import {PRNG} from "seedrandom"; +import { Dict } from './types' +import { PRNG } from 'seedrandom' export function isNonNullable(any: T): any is NonNullable { return any !== undefined && any !== null @@ -29,12 +29,12 @@ export function uniquify(array: T[]): T[] { export function shuffleInplace(array: T[], rng: PRNG): T[] { for (let i = array.length - 1; i > 0; i--) { - const j = Math.floor(rng.quick() * (i + 1)); - [array[i], array[j]] = [array[j], array[i]]; + const j = Math.floor(rng.quick() * (i + 1)) + ;[array[i], array[j]] = [array[j], array[i]] } return array } export function fixedEncodeURIComponent(str: string): string { - return encodeURIComponent(str).replace(/[!'()*]/g, c => '%' + c.charCodeAt(0).toString(16)); + return encodeURIComponent(str).replace(/[!'()*]/g, c => '%' + c.charCodeAt(0).toString(16)) } diff --git a/src/utils/Resolvable.ts b/src/utils/Resolvable.ts index 1dd26c1..f890f26 100644 --- a/src/utils/Resolvable.ts +++ b/src/utils/Resolvable.ts @@ -32,6 +32,7 @@ class FetchOnce { this.pendingList.push([resolve, reject]) break case ResolvableState.DONE: + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion resolve(this.data!) break case ResolvableState.ERROR: diff --git a/src/utils/errors.ts b/src/utils/errors.ts index 019a383..d701887 100644 --- a/src/utils/errors.ts +++ b/src/utils/errors.ts @@ -1,7 +1,6 @@ import { ErrorMessage } from '../types/FrontendApi' -import {NextApiHandler, NextApiRequest, NextApiResponse} from 'next' +import { NextApiHandler, NextApiRequest, NextApiResponse } from 'next' import { logger } from './logger' -import {NextFetchEvent, NextMiddleware, NextRequest} from "next/server"; export class NetworkError extends Error { public content?: ErrorMessage diff --git a/src/utils/logger.ts b/src/utils/logger.ts index 7baf363..5bf1b79 100644 --- a/src/utils/logger.ts +++ b/src/utils/logger.ts @@ -1,3 +1,4 @@ +/* eslint-disable no-console */ export const logger = { verbose: console.log, debug: console.log, diff --git a/src/validation/index.ts b/src/validation/index.ts index 83e6a79..04d52b3 100644 --- a/src/validation/index.ts +++ b/src/validation/index.ts @@ -6,9 +6,11 @@ import { compile, JSONSchema } from 'json-schema-to-typescript' import * as fs from 'fs/promises' import { join } from 'path' import { NetworkError } from '../utils/errors' -import getConfig from "next/config"; +import getConfig from 'next/config' -const {publicRuntimeConfig: {TENANT_TYPE}} = getConfig() +const { + publicRuntimeConfig: { TENANT_TYPE } +} = getConfig() const validatorStorage = new Validator() diff --git a/src/validation/schemas.ts b/src/validation/schemas.ts index 7b53628..0513aa5 100644 --- a/src/validation/schemas.ts +++ b/src/validation/schemas.ts @@ -16,9 +16,9 @@ export function addSchemas() { type: 'object', required: ['type', 'factories'], properties: { - type: {type: 'string', enum: ['exports', 'malls']}, - factories: {type: 'array', items: {type: 'string', minLength: 3}} - }, + type: { type: 'string', enum: ['exports', 'malls'] }, + factories: { type: 'array', items: { type: 'string', minLength: 3 } } + } }, { id: 'GroupIdParam', @@ -34,16 +34,16 @@ export function addSchemas() { type: 'object', required: ['type', 'factories'], properties: { - type: {type: 'string', enum: ['ignored', 'base']}, - factories: {type: 'array', items: {type: 'string', minLength: 3}} - }, + type: { type: 'string', enum: ['ignored', 'base'] }, + factories: { type: 'array', items: { type: 'string', minLength: 3 } } + } }, { id: 'IdParam', type: 'object', required: ['id'], properties: { - id: { type: 'string', minLength: 24, maxLength: 24 }, + id: { type: 'string', minLength: 24, maxLength: 24 } } } ]) diff --git a/styles/globals.css b/styles/globals.css index 940a316..08c2756 100644 --- a/styles/globals.css +++ b/styles/globals.css @@ -1,57 +1,68 @@ html, body { - padding: 0; - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, - Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif; + padding: 0; + margin: 0; + font-family: + -apple-system, + BlinkMacSystemFont, + "Segoe UI", + Roboto, + Oxygen, + Ubuntu, + Cantarell, + "Fira Sans", + "Droid Sans", + "Helvetica Neue", + sans-serif; } body { - color: black; - background: #FAFAFA; - padding: 2em; + padding: 2em; + background: #fafafa; + color: black; } body.scroll { - width: 100vw; - height: 100vh; - padding: 0; + width: 100vw; + height: 100vh; + padding: 0; } a { - color: inherit; - text-decoration: none; + color: inherit; + text-decoration: none; } * { - box-sizing: border-box; + box-sizing: border-box; } :is(h1, h2, h3, h4, h5, h6):is(:first-child) { - margin-block-start: 0; + margin-block-start: 0; } h3 { - margin-block: 1.5em 1em; + margin-block: 1.5em 1em; } h4 { - margin-block: 1em 0.3em; - font-weight: 500; + font-weight: 500; + margin-block: 1em 0.3em; } @media (prefers-color-scheme: dark) { - html { - color-scheme: dark; - } - body { - color: white; - background: #111; - } + html { + color-scheme: dark; + } + + body { + background: #111; + color: white; + } } @media (max-width: 1200px) { - body { - padding-inline: 0.5em; - } + body { + padding-inline: 0.5em; + } } diff --git a/tsconfig.test.json b/tsconfig.test.json new file mode 100644 index 0000000..ae129f9 --- /dev/null +++ b/tsconfig.test.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "include": [ + "**/*.spec.ts", + "**/*.test.ts", + "jest.config.js", + "next.config.js", + "src/backend-custom-server/index", + "scripts/*" + ], + "exclude": ["dist", ".next", "out", "node_modules", "cypress"] +} diff --git a/yarn.lock b/yarn.lock index c0f29f2..0834564 100644 --- a/yarn.lock +++ b/yarn.lock @@ -81,6 +81,11 @@ call-me-maybe "^1.0.1" js-yaml "^4.1.0" +"@csstools/selector-specificity@^2.0.2": + version "2.0.2" + resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-2.0.2.tgz#1bfafe4b7ed0f3e4105837e056e0a89b108ebe36" + integrity sha512-IkpVW/ehM1hWKln4fCA3NzJU8KwD+kIOvPZA4cqxoJHtE21CCzjyp+Kxbu0i5I4tBNOlXPL9mjwnWlL0VEG4Fg== + "@emotion/babel-plugin@^11.10.0": version "11.10.0" resolved "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.10.0.tgz" @@ -321,7 +326,7 @@ "@types/minimatch" "*" "@types/node" "*" -"@types/json-schema@^7.0.11", "@types/json-schema@^7.0.6": +"@types/json-schema@^7.0.11", "@types/json-schema@^7.0.6", "@types/json-schema@^7.0.9": version "7.0.11" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.11.tgz#d421b6c527a3037f7c84433fd2c4229e016863d3" integrity sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ== @@ -341,6 +346,11 @@ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ== +"@types/minimist@^1.2.0": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c" + integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== + "@types/node@*": version "18.7.6" resolved "https://registry.npmjs.org/@types/node/-/node-18.7.6.tgz" @@ -351,6 +361,11 @@ resolved "https://registry.npmjs.org/@types/node/-/node-18.6.4.tgz" integrity sha512-I4BD3L+6AWiUobfxZ49DlU43gtI+FTHSv9pE2Zekg6KjMpre4ByusaljW3vYSLJrvQ1ck1hUaeVu8HVlY3vzHg== +"@types/normalize-package-data@^2.4.0": + version "2.4.1" + resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz#d3357479a0fdfdd5907fe67e17e0a85c906e1301" + integrity sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw== + "@types/pako@^2.0.0": version "2.0.0" resolved "https://registry.npmjs.org/@types/pako/-/pako-2.0.0.tgz" @@ -417,6 +432,21 @@ "@types/node" "*" "@types/webidl-conversions" "*" +"@typescript-eslint/eslint-plugin@^5.33.1": + version "5.33.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.33.1.tgz#c0a480d05211660221eda963cc844732fe9b1714" + integrity sha512-S1iZIxrTvKkU3+m63YUOxYPKaP+yWDQrdhxTglVDVEVBf+aCSw85+BmJnyUaQQsk5TXFG/LpBu9fa+LrAQ91fQ== + dependencies: + "@typescript-eslint/scope-manager" "5.33.1" + "@typescript-eslint/type-utils" "5.33.1" + "@typescript-eslint/utils" "5.33.1" + debug "^4.3.4" + functional-red-black-tree "^1.0.1" + ignore "^5.2.0" + regexpp "^3.2.0" + semver "^7.3.7" + tsutils "^3.21.0" + "@typescript-eslint/parser@^5.21.0": version "5.33.0" resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.33.0.tgz" @@ -427,6 +457,16 @@ "@typescript-eslint/typescript-estree" "5.33.0" debug "^4.3.4" +"@typescript-eslint/parser@^5.33.1": + version "5.33.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-5.33.1.tgz#e4b253105b4d2a4362cfaa4e184e2d226c440ff3" + integrity sha512-IgLLtW7FOzoDlmaMoXdxG8HOCByTBXrB1V2ZQYSEV1ggMmJfAkMWTwUjjzagS6OkfpySyhKFkBw7A9jYmcHpZA== + dependencies: + "@typescript-eslint/scope-manager" "5.33.1" + "@typescript-eslint/types" "5.33.1" + "@typescript-eslint/typescript-estree" "5.33.1" + debug "^4.3.4" + "@typescript-eslint/scope-manager@5.33.0": version "5.33.0" resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.33.0.tgz" @@ -435,11 +475,33 @@ "@typescript-eslint/types" "5.33.0" "@typescript-eslint/visitor-keys" "5.33.0" +"@typescript-eslint/scope-manager@5.33.1": + version "5.33.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-5.33.1.tgz#8d31553e1b874210018ca069b3d192c6d23bc493" + integrity sha512-8ibcZSqy4c5m69QpzJn8XQq9NnqAToC8OdH/W6IXPXv83vRyEDPYLdjAlUx8h/rbusq6MkW4YdQzURGOqsn3CA== + dependencies: + "@typescript-eslint/types" "5.33.1" + "@typescript-eslint/visitor-keys" "5.33.1" + +"@typescript-eslint/type-utils@5.33.1": + version "5.33.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-5.33.1.tgz#1a14e94650a0ae39f6e3b77478baff002cec4367" + integrity sha512-X3pGsJsD8OiqhNa5fim41YtlnyiWMF/eKsEZGsHID2HcDqeSC5yr/uLOeph8rNF2/utwuI0IQoAK3fpoxcLl2g== + dependencies: + "@typescript-eslint/utils" "5.33.1" + debug "^4.3.4" + tsutils "^3.21.0" + "@typescript-eslint/types@5.33.0": version "5.33.0" resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.33.0.tgz" integrity sha512-nIMt96JngB4MYFYXpZ/3ZNU4GWPNdBbcB5w2rDOCpXOVUkhtNlG2mmm8uXhubhidRZdwMaMBap7Uk8SZMU/ppw== +"@typescript-eslint/types@5.33.1": + version "5.33.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-5.33.1.tgz#3faef41793d527a519e19ab2747c12d6f3741ff7" + integrity sha512-7K6MoQPQh6WVEkMrMW5QOA5FO+BOwzHSNd0j3+BlBwd6vtzfZceJ8xJ7Um2XDi/O3umS8/qDX6jdy2i7CijkwQ== + "@typescript-eslint/typescript-estree@5.33.0": version "5.33.0" resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.33.0.tgz" @@ -453,6 +515,31 @@ semver "^7.3.7" tsutils "^3.21.0" +"@typescript-eslint/typescript-estree@5.33.1": + version "5.33.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-5.33.1.tgz#a573bd360790afdcba80844e962d8b2031984f34" + integrity sha512-JOAzJ4pJ+tHzA2pgsWQi4804XisPHOtbvwUyqsuuq8+y5B5GMZs7lI1xDWs6V2d7gE/Ez5bTGojSK12+IIPtXA== + dependencies: + "@typescript-eslint/types" "5.33.1" + "@typescript-eslint/visitor-keys" "5.33.1" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + semver "^7.3.7" + tsutils "^3.21.0" + +"@typescript-eslint/utils@5.33.1": + version "5.33.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-5.33.1.tgz#171725f924fe1fe82bb776522bb85bc034e88575" + integrity sha512-uphZjkMaZ4fE8CR4dU7BquOV6u0doeQAr8n6cQenl/poMaIyJtBu8eys5uk6u5HiDH01Mj5lzbJ5SfeDz7oqMQ== + dependencies: + "@types/json-schema" "^7.0.9" + "@typescript-eslint/scope-manager" "5.33.1" + "@typescript-eslint/types" "5.33.1" + "@typescript-eslint/typescript-estree" "5.33.1" + eslint-scope "^5.1.1" + eslint-utils "^3.0.0" + "@typescript-eslint/visitor-keys@5.33.0": version "5.33.0" resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.33.0.tgz" @@ -461,6 +548,14 @@ "@typescript-eslint/types" "5.33.0" eslint-visitor-keys "^3.3.0" +"@typescript-eslint/visitor-keys@5.33.1": + version "5.33.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-5.33.1.tgz#0155c7571c8cd08956580b880aea327d5c34a18b" + integrity sha512-nwIxOK8Z2MPWltLKMLOEZwmfBZReqUdbEoHQXeCpa+sRVARe5twpJGHCB4dk9903Yaf0nMAlGbQfaAH92F60eg== + dependencies: + "@typescript-eslint/types" "5.33.1" + eslint-visitor-keys "^3.3.0" + acorn-jsx@^5.3.2: version "5.3.2" resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" @@ -471,6 +566,14 @@ acorn@^8.8.0: resolved "https://registry.npmjs.org/acorn/-/acorn-8.8.0.tgz" integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w== +aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + ajv@^6.10.0, ajv@^6.12.4: version "6.12.6" resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" @@ -481,11 +584,33 @@ ajv@^6.10.0, ajv@^6.12.4: json-schema-traverse "^0.4.1" uri-js "^4.2.2" +ajv@^8.0.1: + version "8.11.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.11.0.tgz#977e91dd96ca669f54a11e23e378e33b884a565f" + integrity sha512-wGgprdCvMalC0BztXvitD2hC04YffAvtsUn93JbGXYLAtCUO4xd17mCCZQxUOItiBwZvJScWo8NIvQMQ71rdpg== + dependencies: + fast-deep-equal "^3.1.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + uri-js "^4.2.2" + +ansi-escapes@^4.3.0: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== +ansi-regex@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.0.1.tgz#3183e38fae9a65d7cb5e53945cd5897d0260a06a" + integrity sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA== + ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" @@ -493,13 +618,18 @@ ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" -ansi-styles@^4.1.0: +ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== dependencies: color-convert "^2.0.1" +ansi-styles@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.1.0.tgz#87313c102b8118abd57371afab34618bf7350ed3" + integrity sha512-VbqNsoz55SYGczauuup0MFUyXNQviSpFTj1RQtFzmQLk18qbVSpTFFGMT293rmDaQuKCT6InmbuEyUne4mTuxQ== + any-promise@^1.0.0: version "1.3.0" resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" @@ -554,11 +684,21 @@ array.prototype.flatmap@^1.3.0: es-abstract "^1.19.2" es-shim-unscopables "^1.0.0" +arrify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA== + ast-types-flow@^0.0.7: version "0.0.7" resolved "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz" integrity sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag== +astral-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" + integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== + axe-core@^4.4.3: version "4.4.3" resolved "https://registry.npmjs.org/axe-core/-/axe-core-4.4.3.tgz" @@ -583,6 +723,11 @@ balanced-match@^1.0.0: resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +balanced-match@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-2.0.0.tgz#dc70f920d78db8b858535795867bf48f820633d9" + integrity sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA== + base64-js@^1.3.1: version "1.5.1" resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" @@ -636,6 +781,20 @@ callsites@^3.0.0: resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== +camelcase-keys@^6.2.2: + version "6.2.2" + resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0" + integrity sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg== + dependencies: + camelcase "^5.3.1" + map-obj "^4.0.0" + quick-lru "^4.0.1" + +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + caniuse-lite@^1.0.30001332: version "1.0.30001374" resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001374.tgz" @@ -663,6 +822,11 @@ classnames@^2.2.6, classnames@^2.3.1: resolved "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz" integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA== +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + cli-color@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/cli-color/-/cli-color-2.0.3.tgz#73769ba969080629670f3f2ef69a4bf4e7cc1879" @@ -674,6 +838,29 @@ cli-color@^2.0.2: memoizee "^0.4.15" timers-ext "^0.1.7" +cli-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== + dependencies: + restore-cursor "^3.1.0" + +cli-truncate@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7" + integrity sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg== + dependencies: + slice-ansi "^3.0.0" + string-width "^4.2.0" + +cli-truncate@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-3.1.0.tgz#3f23ab12535e3d73e839bb43e73c9de487db1389" + integrity sha512-wfOBkjXteqSnI59oPcJkcPl/ZmwvMMOj340qUIY1SKZCv0B9Cf4D4fAucRkIKQmsIuYK3x1rrgU7MeGRruiuiA== + dependencies: + slice-ansi "^5.0.0" + string-width "^5.0.0" + color-convert@^1.9.0: version "1.9.3" resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" @@ -698,6 +885,21 @@ color-name@~1.1.4: resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +colord@^2.9.2: + version "2.9.3" + resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.3.tgz#4f8ce919de456f1d5c1c368c307fe20f3e59fb43" + integrity sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw== + +colorette@^2.0.16, colorette@^2.0.17: + version "2.0.19" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798" + integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ== + +commander@^9.3.0: + version "9.4.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-9.4.0.tgz#bc4a40918fefe52e22450c111ecd6b7acce6f11c" + integrity sha512-sRPT+umqkz90UA8M1yqYfnHlZA7fF6nSphDtxeywPZ49ysjxDQybzk13CL+mXekDRG92skbcqCLVovuCusNmFw== + concat-map@0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" @@ -715,7 +917,7 @@ core-js-pure@^3.20.2: resolved "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.24.1.tgz" integrity sha512-r1nJk41QLLPyozHUUPmILCEMtMw24NG4oWK6RbsDdjzQgg9ZvrUsPBj1MnG0wXXp1DCDU6j+wUvEmBSrtRbLXg== -cosmiconfig@^7.0.0: +cosmiconfig@^7.0.0, cosmiconfig@^7.0.1: version "7.0.1" resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz" integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ== @@ -726,7 +928,7 @@ cosmiconfig@^7.0.0: path-type "^4.0.0" yaml "^1.10.0" -cross-spawn@^7.0.2: +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" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== @@ -735,6 +937,16 @@ cross-spawn@^7.0.2: shebang-command "^2.0.0" which "^2.0.1" +css-functions-list@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/css-functions-list/-/css-functions-list-3.1.0.tgz#cf5b09f835ad91a00e5959bcfc627cd498e1321b" + integrity sha512-/9lCvYZaUbBGvYUgYGFJ4dcYiyqdhSjG7IPVluoV8A1ILjkF7ilmhp1OGUz8n+nmBcu0RNrQAzgD8B6FJbrt2w== + +cssesc@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== + csstype@^3.0.2: version "3.1.0" resolved "https://registry.npmjs.org/csstype/-/csstype-3.1.0.tgz" @@ -779,6 +991,19 @@ debug@^4.1.1, debug@^4.3.2, debug@^4.3.4: dependencies: ms "2.1.2" +decamelize-keys@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" + integrity sha512-ocLWuYzRPoS9bfiSdDd3cxvrzovVMZnRDVEzAs+hWIVXGDbHxWMECij2OBuyB/An0FFW/nLuq6Kv1i/YC5Qfzg== + dependencies: + decamelize "^1.1.0" + map-obj "^1.0.0" + +decamelize@^1.1.0, decamelize@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== + deep-is@^0.1.3: version "0.1.4" resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" @@ -833,11 +1058,21 @@ dom-helpers@^5.0.1: "@babel/runtime" "^7.8.7" csstype "^3.0.2" +eastasianwidth@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" + integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== + easy-bem@^1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/easy-bem/-/easy-bem-1.1.1.tgz" integrity sha512-GJRqdiy2h+EXy6a8E6R+ubmqUM08BK0FWNq41k24fup6045biQ8NXxoXimiwegMQvFFV3t1emADdGNL1TlS61A== +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + emoji-regex@^9.2.2: version "9.2.2" resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz" @@ -1051,6 +1286,26 @@ eslint-plugin-react@^7.29.4: semver "^6.3.0" string.prototype.matchall "^4.0.7" +eslint-plugin-unused-imports@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-2.0.0.tgz#d8db8c4d0cfa0637a8b51ce3fd7d1b6bc3f08520" + integrity sha512-3APeS/tQlTrFa167ThtP0Zm0vctjr4M44HMpeg1P4bK6wItarumq0Ma82xorMKdFsWpphQBlRPzw/pxiVELX1A== + dependencies: + eslint-rule-composer "^0.3.0" + +eslint-rule-composer@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz#79320c927b0c5c0d3d3d2b76c8b4a488f25bbaf9" + integrity sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg== + +eslint-scope@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" + integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== + dependencies: + esrecurse "^4.3.0" + estraverse "^4.1.1" + eslint-scope@^7.1.1: version "7.1.1" resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz" @@ -1144,6 +1399,11 @@ esrecurse@^4.3.0: dependencies: estraverse "^5.2.0" +estraverse@^4.1.1: + version "4.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== + estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: version "5.3.0" resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" @@ -1162,6 +1422,21 @@ event-emitter@^0.3.5: d "1" es5-ext "~0.10.14" +execa@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/execa/-/execa-6.1.0.tgz#cea16dee211ff011246556388effa0818394fb20" + integrity sha512-QVWlX2e50heYJcCPG0iWtf8r0xjEYfz/OYLGDYH+IyjWezzPNxz63qNFOu0l4YftGWuizFVZHHs8PrLU5p2IDA== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.1" + human-signals "^3.0.1" + is-stream "^3.0.0" + merge-stream "^2.0.0" + npm-run-path "^5.1.0" + onetime "^6.0.0" + signal-exit "^3.0.7" + strip-final-newline "^3.0.0" + ext@^1.1.2: version "1.6.0" resolved "https://registry.yarnpkg.com/ext/-/ext-1.6.0.tgz#3871d50641e874cc172e2b53f919842d19db4c52" @@ -1174,7 +1449,7 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-glob@^3.2.9: +fast-glob@^3.2.11, fast-glob@^3.2.9: version "3.2.11" resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz" integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== @@ -1195,6 +1470,11 @@ fast-levenshtein@^2.0.6: resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== +fastest-levenshtein@^1.0.16: + version "1.0.16" + resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz#210e61b6ff181de91ea9b3d1b84fdedd47e034e5" + integrity sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg== + fastq@^1.6.0: version "1.13.0" resolved "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz" @@ -1228,6 +1508,14 @@ find-up@^2.1.0: dependencies: locate-path "^2.0.0" +find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + find-up@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" @@ -1293,6 +1581,11 @@ get-stdin@^8.0.0: resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-8.0.0.tgz#cbad6a73feb75f6eeb22ba9e01f89aa28aa97a53" integrity sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg== +get-stream@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + get-symbol-description@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz" @@ -1346,6 +1639,22 @@ glob@^7.1.3, glob@^7.1.6, glob@^7.2.0: once "^1.3.0" path-is-absolute "^1.0.0" +global-modules@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780" + integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A== + dependencies: + global-prefix "^3.0.0" + +global-prefix@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97" + integrity sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg== + dependencies: + ini "^1.3.5" + kind-of "^6.0.2" + which "^1.3.1" + globals@^13.15.0: version "13.17.0" resolved "https://registry.npmjs.org/globals/-/globals-13.17.0.tgz" @@ -1365,11 +1674,21 @@ globby@^11.1.0: merge2 "^1.4.1" slash "^3.0.0" +globjoin@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/globjoin/-/globjoin-0.1.4.tgz#2f4494ac8919e3767c5cbb691e9f463324285d43" + integrity sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg== + grapheme-splitter@^1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz" integrity sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ== +hard-rejection@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" + integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== + 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" @@ -1418,6 +1737,33 @@ hoist-non-react-statics@^3.3.1, hoist-non-react-statics@^3.3.2: dependencies: react-is "^16.7.0" +hosted-git-info@^2.1.4: + version "2.8.9" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" + integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== + +hosted-git-info@^4.0.1: + version "4.1.0" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.1.0.tgz#827b82867e9ff1c8d0c4d9d53880397d2c86d224" + integrity sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA== + dependencies: + lru-cache "^6.0.0" + +html-tags@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.2.0.tgz#dbb3518d20b726524e4dd43de397eb0a95726961" + integrity sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg== + +human-signals@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-3.0.1.tgz#c740920859dafa50e5a3222da9d3bf4bb0e5eef5" + integrity sha512-rQLskxnM/5OCldHo+wNXbpVgDn5A17CUoKX+7Sokwaknlq7CdSnphy0W39GU8dw59XiCXmFXDg4fRuckQRKewQ== + +husky@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/husky/-/husky-8.0.1.tgz#511cb3e57de3e3190514ae49ed50f6bc3f50b3e9" + integrity sha512-xs7/chUH/CKdOCs7Zy0Aev9e/dKOMZf3K1Az1nar3tzlv0jfqnYtu235bstsWTmXOR0EfINrPa97yy4Lz6RiKw== + ieee754@^1.1.13: version "1.2.1" resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" @@ -1436,11 +1782,21 @@ import-fresh@^3.0.0, import-fresh@^3.2.1: parent-module "^1.0.0" resolve-from "^4.0.0" +import-lazy@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-4.0.0.tgz#e8eb627483a0a43da3c03f3e35548be5cb0cc153" + integrity sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw== + imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + inflight@^1.0.4: version "1.0.6" resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" @@ -1454,6 +1810,11 @@ inherits@2: resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +ini@^1.3.5: + version "1.3.8" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" + integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== + internal-slot@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz" @@ -1493,7 +1854,7 @@ is-callable@^1.1.4, is-callable@^1.2.4: resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz" integrity sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w== -is-core-module@^2.8.1, is-core-module@^2.9.0: +is-core-module@^2.5.0, is-core-module@^2.8.1, is-core-module@^2.9.0: version "2.10.0" resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz" integrity sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg== @@ -1512,6 +1873,16 @@ is-extglob@^2.1.1: resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-fullwidth-code-point@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz#fae3167c729e7463f8461ce512b080a49268aa88" + integrity sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ== + is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: version "4.0.3" resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" @@ -1536,6 +1907,16 @@ is-number@^7.0.0: resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== +is-plain-obj@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + integrity sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg== + +is-plain-object@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" + integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== + is-promise@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.2.2.tgz#39ab959ccbf9a774cf079f7b40c7a26f763135f1" @@ -1556,6 +1937,11 @@ is-shared-array-buffer@^1.0.2: dependencies: call-bind "^1.0.2" +is-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" + integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== + is-string@^1.0.5, is-string@^1.0.7: version "1.0.7" resolved "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz" @@ -1624,6 +2010,11 @@ json-schema-traverse@^0.4.1: resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + json-stable-stringify-without-jsonify@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" @@ -1649,6 +2040,16 @@ jsonschema@^1.4.1: array-includes "^3.1.5" object.assign "^4.1.3" +kind-of@^6.0.2, kind-of@^6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== + +known-css-properties@^0.25.0: + version "0.25.0" + resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.25.0.tgz#6ebc4d4b412f602e5cfbeb4086bd544e34c0a776" + integrity sha512-b0/9J1O9Jcyik1GC6KC42hJ41jKwdO/Mq8Mdo5sYN+IuRTXs2YFHZC3kZSx6ueusqa95x3wLYe/ytKjbAfGixA== + language-subtag-registry@~0.3.2: version "0.3.22" resolved "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz" @@ -1669,11 +2070,49 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" +lilconfig@2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.5.tgz#19e57fd06ccc3848fd1891655b5a447092225b25" + integrity sha512-xaYmXZtTHPAw5m+xLN8ab9C+3a8YmV3asNSPOATITbtwrfbwaLJj8h66H1WMIpALCkqsIzK3h7oQ+PdX+LQ9Eg== + lines-and-columns@^1.1.6: version "1.2.4" resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz" integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== +lint-staged@^13.0.3: + version "13.0.3" + resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-13.0.3.tgz#d7cdf03a3830b327a2b63c6aec953d71d9dc48c6" + integrity sha512-9hmrwSCFroTSYLjflGI8Uk+GWAwMB4OlpU4bMJEAT5d/llQwtYKoim4bLOyLCuWFAhWEupE0vkIFqtw/WIsPug== + dependencies: + cli-truncate "^3.1.0" + colorette "^2.0.17" + commander "^9.3.0" + debug "^4.3.4" + execa "^6.1.0" + lilconfig "2.0.5" + listr2 "^4.0.5" + micromatch "^4.0.5" + normalize-path "^3.0.0" + object-inspect "^1.12.2" + pidtree "^0.6.0" + string-argv "^0.3.1" + yaml "^2.1.1" + +listr2@^4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/listr2/-/listr2-4.0.5.tgz#9dcc50221583e8b4c71c43f9c7dfd0ef546b75d5" + integrity sha512-juGHV1doQdpNT3GSTs9IUN43QJb7KHdF9uqg7Vufs/tG9VTzpFphqF4pm/ICdAABGQxsyNn9CiYA3StkI6jpwA== + dependencies: + cli-truncate "^2.1.0" + colorette "^2.0.16" + log-update "^4.0.0" + p-map "^4.0.0" + rfdc "^1.3.0" + rxjs "^7.5.5" + through "^2.3.8" + wrap-ansi "^7.0.0" + locate-path@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz" @@ -1682,6 +2121,13 @@ locate-path@^2.0.0: p-locate "^2.0.0" path-exists "^3.0.0" +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + locate-path@^6.0.0: version "6.0.0" resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz" @@ -1694,11 +2140,26 @@ lodash.merge@^4.6.2: resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -lodash@^4.17.21: +lodash.truncate@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" + integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== + +lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.21: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== +log-update@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1" + integrity sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg== + dependencies: + ansi-escapes "^4.3.0" + cli-cursor "^3.1.0" + slice-ansi "^4.0.0" + wrap-ansi "^6.2.0" + loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" @@ -1720,6 +2181,21 @@ lru-queue@^0.1.0: dependencies: es5-ext "~0.10.2" +map-obj@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" + integrity sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg== + +map-obj@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.3.0.tgz#9304f906e93faae70880da102a9f1df0ea8bb05a" + integrity sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ== + +mathml-tag-names@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.3.tgz#4ddadd67308e780cf16a47685878ee27b736a0a3" + integrity sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg== + memoize-one@^5.0.0: version "5.2.1" resolved "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz" @@ -1744,12 +2220,35 @@ memory-pager@^1.0.2: resolved "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz" integrity sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg== +meow@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/meow/-/meow-9.0.0.tgz#cd9510bc5cac9dee7d03c73ee1f9ad959f4ea364" + integrity sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ== + dependencies: + "@types/minimist" "^1.2.0" + camelcase-keys "^6.2.2" + decamelize "^1.2.0" + decamelize-keys "^1.1.0" + hard-rejection "^2.1.0" + minimist-options "4.1.0" + normalize-package-data "^3.0.0" + read-pkg-up "^7.0.1" + redent "^3.0.0" + trim-newlines "^3.0.0" + type-fest "^0.18.0" + yargs-parser "^20.2.3" + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -micromatch@^4.0.4: +micromatch@^4.0.4, micromatch@^4.0.5: version "4.0.5" resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz" integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== @@ -1757,6 +2256,21 @@ micromatch@^4.0.4: braces "^3.0.2" picomatch "^2.3.1" +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +mimic-fn@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" + integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== + +min-indent@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" + integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== + minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" @@ -1764,6 +2278,15 @@ minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" +minimist-options@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" + integrity sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A== + dependencies: + arrify "^1.0.1" + is-plain-obj "^1.1.0" + kind-of "^6.0.3" + minimist@^1.2.0, minimist@^1.2.6: version "1.2.6" resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz" @@ -1866,12 +2389,44 @@ next@12.2.4: "@next/swc-win32-ia32-msvc" "12.2.4" "@next/swc-win32-x64-msvc" "12.2.4" +normalize-package-data@^2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== + dependencies: + hosted-git-info "^2.1.4" + resolve "^1.10.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-package-data@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.3.tgz#dbcc3e2da59509a0983422884cd172eefdfa525e" + integrity sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA== + dependencies: + hosted-git-info "^4.0.1" + is-core-module "^2.5.0" + semver "^7.3.4" + validate-npm-package-license "^3.0.1" + +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-run-path@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.1.0.tgz#bc62f7f3f6952d9894bd08944ba011a6ee7b7e00" + integrity sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q== + dependencies: + path-key "^4.0.0" + object-assign@^4.0.1, object-assign@^4.1.1: version "4.1.1" resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== -object-inspect@^1.12.0, object-inspect@^1.9.0: +object-inspect@^1.12.0, object-inspect@^1.12.2, object-inspect@^1.9.0: version "1.12.2" resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.2.tgz" integrity sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ== @@ -1933,6 +2488,20 @@ once@^1.3.0: dependencies: wrappy "1" +onetime@^5.1.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +onetime@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-6.0.0.tgz#7c24c18ed1fd2e9bca4bd26806a33613c77d34b4" + integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ== + dependencies: + mimic-fn "^4.0.0" + optionator@^0.9.1: version "0.9.1" resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz" @@ -1952,6 +2521,13 @@ p-limit@^1.1.0: dependencies: p-try "^1.0.0" +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + p-limit@^3.0.2: version "3.1.0" resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" @@ -1966,6 +2542,13 @@ p-locate@^2.0.0: dependencies: p-limit "^1.1.0" +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + p-locate@^5.0.0: version "5.0.0" resolved "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz" @@ -1973,11 +2556,23 @@ p-locate@^5.0.0: 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" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== + dependencies: + aggregate-error "^3.0.0" + p-try@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz" integrity sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww== +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + pako@^2.0.4: version "2.0.4" resolved "https://registry.npmjs.org/pako/-/pako-2.0.4.tgz" @@ -2020,6 +2615,11 @@ path-key@^3.1.0: resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== +path-key@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18" + integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== + path-parse@^1.0.7: version "1.0.7" resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" @@ -2030,6 +2630,11 @@ path-type@^4.0.0: resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== +picocolors@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-0.2.1.tgz#570670f793646851d1ba135996962abad587859f" + integrity sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA== + picocolors@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz" @@ -2040,6 +2645,47 @@ picomatch@^2.3.1: resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +pidtree@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.6.0.tgz#90ad7b6d42d5841e69e0a2419ef38f8883aa057c" + integrity sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g== + +postcss-media-query-parser@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz#27b39c6f4d94f81b1a73b8f76351c609e5cef244" + integrity sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig== + +postcss-resolve-nested-selector@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz#29ccbc7c37dedfac304e9fff0bf1596b3f6a0e4e" + integrity sha512-HvExULSwLqHLgUy1rl3ANIqCsvMS0WHss2UOsXhXnQaZ9VCc2oBvIpXrl00IUFT5ZDITME0o6oiXeiHr2SAIfw== + +postcss-safe-parser@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz#bb4c29894171a94bc5c996b9a30317ef402adaa1" + integrity sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ== + +postcss-selector-parser@^6.0.10: + version "6.0.10" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz#79b61e2c0d1bfc2602d549e11d0876256f8df88d" + integrity sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w== + dependencies: + cssesc "^3.0.0" + util-deprecate "^1.0.2" + +postcss-sorting@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/postcss-sorting/-/postcss-sorting-5.0.1.tgz#10d5d0059eea8334dacc820c0121864035bc3f11" + integrity sha512-Y9fUFkIhfrm6i0Ta3n+89j56EFqaNRdUKqXyRp6kvTcSXnmgEjaVowCXH+JBe9+YKWqd4nc28r2sgwnzJalccA== + dependencies: + lodash "^4.17.14" + postcss "^7.0.17" + +postcss-value-parser@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514" + integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== + postcss@8.4.14: version "8.4.14" resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz" @@ -2049,12 +2695,29 @@ postcss@8.4.14: picocolors "^1.0.0" source-map-js "^1.0.2" +postcss@^7.0.17: + version "7.0.39" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.39.tgz#9624375d965630e2e1f2c02a935c82a59cb48309" + integrity sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA== + dependencies: + picocolors "^0.2.1" + source-map "^0.6.1" + +postcss@^8.4.16: + version "8.4.16" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.16.tgz#33a1d675fac39941f5f445db0de4db2b6e01d43c" + integrity sha512-ipHE1XBvKzm5xI7hiHCZJCSugxvsdq2mPnsq5+UF+VHCjiBvtDrlxJfMBToWaP9D5XlgNmcFGqoHmUn0EYEaRQ== + dependencies: + nanoid "^3.3.4" + picocolors "^1.0.0" + source-map-js "^1.0.2" + prelude-ls@^1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -prettier@^2.6.2: +prettier@^2.6.2, prettier@^2.7.1: version "2.7.1" resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64" integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g== @@ -2078,6 +2741,11 @@ queue-microtask@^1.2.2: resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== +quick-lru@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" + integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g== + react-dom@18.2.0: version "18.2.0" resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz" @@ -2138,6 +2806,33 @@ react@18.2.0: dependencies: loose-envify "^1.1.0" +read-pkg-up@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" + integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== + dependencies: + find-up "^4.1.0" + read-pkg "^5.2.0" + type-fest "^0.8.1" + +read-pkg@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" + integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== + dependencies: + "@types/normalize-package-data" "^2.4.0" + normalize-package-data "^2.5.0" + parse-json "^5.0.0" + type-fest "^0.6.0" + +redent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" + integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg== + dependencies: + indent-string "^4.0.0" + strip-indent "^3.0.0" + regenerator-runtime@^0.13.4: version "0.13.9" resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz" @@ -2157,12 +2852,22 @@ regexpp@^3.2.0: resolved "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz" integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== -resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.0: +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve@^1.10.0, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.0: version "1.22.1" resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz" integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw== @@ -2180,11 +2885,24 @@ resolve@^2.0.0-next.3: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +restore-cursor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== + dependencies: + onetime "^5.1.0" + signal-exit "^3.0.2" + reusify@^1.0.4: version "1.0.4" resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== +rfdc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" + integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== + rimraf@^3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" @@ -2199,6 +2917,13 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" +rxjs@^7.5.5: + version "7.5.6" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.5.6.tgz#0446577557862afd6903517ce7cae79ecb9662bc" + integrity sha512-dnyv2/YsXhnm461G+R/Pe5bWP41Nm6LBXEYWI6eiFP4fiwx6WRI/CD0zbdVAudd9xwLEF2IDcKXLHit0FYjUzw== + dependencies: + tslib "^2.1.0" + safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" @@ -2223,12 +2948,17 @@ seedrandom@^3.0.5: resolved "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz" integrity sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg== +"semver@2 || 3 || 4 || 5": + version "5.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== + semver@^6.3.0: version "6.3.0" resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@^7.3.7: +semver@^7.3.4, semver@^7.3.7: version "7.3.7" resolved "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz" integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g== @@ -2256,11 +2986,42 @@ side-channel@^1.0.4: get-intrinsic "^1.0.2" object-inspect "^1.9.0" +signal-exit@^3.0.2, signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + slash@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== +slice-ansi@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787" + integrity sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +slice-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== + dependencies: + ansi-styles "^4.0.0" + astral-regex "^2.0.0" + is-fullwidth-code-point "^3.0.0" + +slice-ansi@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-5.0.0.tgz#b73063c57aa96f9cd881654b15294d95d285c42a" + integrity sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ== + dependencies: + ansi-styles "^6.0.0" + is-fullwidth-code-point "^4.0.0" + smart-buffer@^4.2.0: version "4.2.0" resolved "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz" @@ -2284,6 +3045,11 @@ source-map@^0.5.7: resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz" integrity sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ== +source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + sparse-bitfield@^3.0.3: version "3.0.3" resolved "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz" @@ -2291,6 +3057,55 @@ sparse-bitfield@^3.0.3: dependencies: memory-pager "^1.0.2" +spdx-correct@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" + integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w== + dependencies: + spdx-expression-parse "^3.0.0" + spdx-license-ids "^3.0.0" + +spdx-exceptions@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" + integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== + +spdx-expression-parse@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== + dependencies: + spdx-exceptions "^2.1.0" + spdx-license-ids "^3.0.0" + +spdx-license-ids@^3.0.0: + version "3.0.11" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz#50c0d8c40a14ec1bf449bae69a0ea4685a9d9f95" + integrity sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g== + +string-argv@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" + integrity sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg== + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^5.0.0: + version "5.1.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" + integrity sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA== + dependencies: + eastasianwidth "^0.2.0" + emoji-regex "^9.2.2" + strip-ansi "^7.0.1" + string.prototype.matchall@^4.0.7: version "4.0.7" resolved "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.7.tgz" @@ -2323,28 +3138,124 @@ string.prototype.trimstart@^1.0.5: define-properties "^1.1.4" es-abstract "^1.19.5" -strip-ansi@^6.0.1: +strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: ansi-regex "^5.0.1" +strip-ansi@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.0.1.tgz#61740a08ce36b61e50e65653f07060d000975fb2" + integrity sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw== + dependencies: + ansi-regex "^6.0.1" + strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz" integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== +strip-final-newline@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd" + integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw== + +strip-indent@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" + integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== + dependencies: + min-indent "^1.0.0" + strip-json-comments@^3.1.0, 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" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== +style-search@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902" + integrity sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg== + styled-jsx@5.0.2: version "5.0.2" resolved "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.0.2.tgz" integrity sha512-LqPQrbBh3egD57NBcHET4qcgshPks+yblyhPlH2GY8oaDgKs8SK4C3dBh3oSJjgzJ3G5t1SYEZGHkP+QEpX9EQ== +stylelint-config-idiomatic-order@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/stylelint-config-idiomatic-order/-/stylelint-config-idiomatic-order-8.1.0.tgz#7ca7fa92eb79369948dd4977499466c844ace21d" + integrity sha512-iTPY6JjbkIdzy+21x3a1xi/tG33zKhLJb6lZl1xg6jZrXjgIYelnRZ5xVtbcEP9rElxZq/Zu1eGthfvI+ri+YQ== + dependencies: + stylelint-order "^3.1.1" + +stylelint-config-recommended@^9.0.0: + version "9.0.0" + resolved "https://registry.yarnpkg.com/stylelint-config-recommended/-/stylelint-config-recommended-9.0.0.tgz#1c9e07536a8cd875405f8ecef7314916d94e7e40" + integrity sha512-9YQSrJq4NvvRuTbzDsWX3rrFOzOlYBmZP+o513BJN/yfEmGSr0AxdvrWs0P/ilSpVV/wisamAHu5XSk8Rcf4CQ== + +stylelint-config-standard@^27.0.0: + version "27.0.0" + resolved "https://registry.yarnpkg.com/stylelint-config-standard/-/stylelint-config-standard-27.0.0.tgz#d1c69082fc973dab7da1a6c89979e54a0758f389" + integrity sha512-J+wxyODWQCW2kgdhVzj51a4cFcJkglkMQrjPU/1Jo8w2oKSKK5ZRqHvDDWxEmjYWIYbMhhIMS5dOgVpGUMIACw== + dependencies: + stylelint-config-recommended "^9.0.0" + +stylelint-order@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/stylelint-order/-/stylelint-order-3.1.1.tgz#ba9ea6844d1482f97f31204e7c9605c7b792c294" + integrity sha512-4gP/r8j/6JGZ/LL41b2sYtQqfwZl4VSqTp7WeIwI67v/OXNQ08dnn64BGXNwAUSgb2+YIvIOxQaMzqMyQMzoyQ== + dependencies: + lodash "^4.17.15" + postcss "^7.0.17" + postcss-sorting "^5.0.1" + +stylelint@^14.10.0: + version "14.10.0" + resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-14.10.0.tgz#c588f5cd47cd214cf1acee5bc165961b6a3ad836" + integrity sha512-VAmyKrEK+wNFh9R8mNqoxEFzaa4gsHGhcT4xgkQDuOA5cjF6CaNS8loYV7gpi4tIZBPUyXesotPXzJAMN8VLOQ== + dependencies: + "@csstools/selector-specificity" "^2.0.2" + balanced-match "^2.0.0" + colord "^2.9.2" + cosmiconfig "^7.0.1" + css-functions-list "^3.1.0" + debug "^4.3.4" + fast-glob "^3.2.11" + fastest-levenshtein "^1.0.16" + file-entry-cache "^6.0.1" + global-modules "^2.0.0" + globby "^11.1.0" + globjoin "^0.1.4" + html-tags "^3.2.0" + ignore "^5.2.0" + import-lazy "^4.0.0" + imurmurhash "^0.1.4" + is-plain-object "^5.0.0" + known-css-properties "^0.25.0" + mathml-tag-names "^2.1.3" + meow "^9.0.0" + micromatch "^4.0.5" + normalize-path "^3.0.0" + picocolors "^1.0.0" + postcss "^8.4.16" + postcss-media-query-parser "^0.2.3" + postcss-resolve-nested-selector "^0.1.1" + postcss-safe-parser "^6.0.0" + postcss-selector-parser "^6.0.10" + postcss-value-parser "^4.2.0" + resolve-from "^5.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + style-search "^0.1.0" + supports-hyperlinks "^2.2.0" + svg-tags "^1.0.0" + table "^6.8.0" + v8-compile-cache "^2.3.0" + write-file-atomic "^4.0.1" + stylis@4.0.13: version "4.0.13" resolved "https://registry.npmjs.org/stylis/-/stylis-4.0.13.tgz" @@ -2357,18 +3268,42 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" -supports-color@^7.1.0: +supports-color@^7.0.0, supports-color@^7.1.0: version "7.2.0" resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== dependencies: has-flag "^4.0.0" +supports-hyperlinks@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz#4f77b42488765891774b70c79babd87f9bd594bb" + integrity sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ== + dependencies: + has-flag "^4.0.0" + supports-color "^7.0.0" + supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== +svg-tags@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764" + integrity sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA== + +table@^6.8.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/table/-/table-6.8.0.tgz#87e28f14fa4321c3377ba286f07b79b281a3b3ca" + integrity sha512-s/fitrbVeEyHKFa7mFdkuQMWlH1Wgw/yEXMt5xACT4ZpzWFluehAxRtUUQKPuWhaLAWhFcVx6w3oC8VKaUfPGA== + dependencies: + ajv "^8.0.1" + lodash.truncate "^4.4.2" + slice-ansi "^4.0.0" + string-width "^4.2.3" + strip-ansi "^6.0.1" + text-table@^0.2.0: version "0.2.0" resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" @@ -2388,6 +3323,11 @@ thenify-all@^1.0.0: dependencies: any-promise "^1.0.0" +through@^2.3.8: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== + timers-ext@^0.1.7: version "0.1.7" resolved "https://registry.yarnpkg.com/timers-ext/-/timers-ext-0.1.7.tgz#6f57ad8578e07a3fb9f91d9387d65647555e25c6" @@ -2415,6 +3355,11 @@ tr46@^3.0.0: dependencies: punycode "^2.1.1" +trim-newlines@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" + integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw== + tsconfig-paths@^3.14.1: version "3.14.1" resolved "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz" @@ -2430,7 +3375,7 @@ tslib@^1.8.1: resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.4.0: +tslib@^2.1.0, tslib@^2.4.0: version "2.4.0" resolved "https://registry.npmjs.org/tslib/-/tslib-2.4.0.tgz" integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== @@ -2454,11 +3399,31 @@ type-detect@^4.0.8: resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== +type-fest@^0.18.0: + version "0.18.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f" + integrity sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw== + type-fest@^0.20.2: version "0.20.2" resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +type-fest@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" + integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== + +type-fest@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== + type@^1.0.1: version "1.2.0" resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" @@ -2496,16 +3461,29 @@ use-sync-external-store@1.2.0: resolved "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz" integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== +util-deprecate@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + uuid@^7.0.3: version "7.0.3" resolved "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz" integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg== -v8-compile-cache@^2.0.3: +v8-compile-cache@^2.0.3, v8-compile-cache@^2.3.0: version "2.3.0" resolved "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== +validate-npm-package-license@^3.0.1: + version "3.0.4" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== + dependencies: + spdx-correct "^3.0.0" + spdx-expression-parse "^3.0.0" + webidl-conversions@^7.0.0: version "7.0.0" resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz" @@ -2530,6 +3508,13 @@ which-boxed-primitive@^1.0.2: is-string "^1.0.5" is-symbol "^1.0.3" +which@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== + dependencies: + isexe "^2.0.0" + which@^2.0.1: version "2.0.2" resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" @@ -2542,11 +3527,37 @@ word-wrap@^1.2.3: resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== +wrap-ansi@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + wrappy@1: version "1.0.2" resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== +write-file-atomic@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" + integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^3.0.7" + yallist@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" @@ -2557,6 +3568,16 @@ yaml@^1.10.0: resolved "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== +yaml@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.1.1.tgz#1e06fb4ca46e60d9da07e4f786ea370ed3c3cfec" + integrity sha512-o96x3OPo8GjWeSLF+wOAbrPfhFOGY0W00GNaxCDv+9hkcDJEnev1yh8S7pgHF0ik6zc8sQLuL8hjHjJULZp8bw== + +yargs-parser@^20.2.3: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz"