From 34de4713681a207865a93ff8acc1bff332caea55 Mon Sep 17 00:00:00 2001 From: Andrey Polischuk Date: Wed, 24 Jan 2024 22:13:06 +0300 Subject: [PATCH] chore: update eslint config and fix errors --- .eslintrc.json | 2 +- jest.config.js | 2 +- package.json | 8 +- src/client/index.ts | 1 + src/client/stream.tsx | 3 +- src/common/json.ts | 24 +- src/components/context.tsx | 6 +- src/components/lazy.tsx | 4 +- src/components/loader.test.tsx | 2 +- src/components/loader.tsx | 8 +- src/components/meta.tsx | 46 +- src/components/routes.tsx | 34 +- src/components/scripts.tsx | 4 +- src/server/index.ts | 1 + src/server/stream.test.tsx | 2 +- src/server/stream.tsx | 10 +- src/test/components/custom-context.tsx | 9 +- src/test/components/document.tsx | 8 +- src/test/components/get-async-data.tsx | 14 +- src/test/components/get-data.tsx | 2 +- src/test/components/home.tsx | 14 +- src/test/components/layout.tsx | 8 +- src/test/components/location.tsx | 18 +- src/test/components/param.tsx | 14 - src/test/components/parameter.tsx | 16 + src/test/components/static-import.tsx | 14 +- src/test/routes.tsx | 4 +- tsconfig.json | 5 +- yarn.lock | 897 ++++++++++++++++++------- 29 files changed, 797 insertions(+), 383 deletions(-) delete mode 100644 src/test/components/param.tsx create mode 100644 src/test/components/parameter.tsx diff --git a/.eslintrc.json b/.eslintrc.json index 4f7a449..cd9a492 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,8 +1,8 @@ { "extends": [ "@rambler-tech/eslint-config", - "@rambler-tech/eslint-config/ts", "@rambler-tech/eslint-config/react", + "@rambler-tech/eslint-config/ts", "prettier" ] } diff --git a/jest.config.js b/jest.config.js index 57870be..f1b1128 100644 --- a/jest.config.js +++ b/jest.config.js @@ -6,7 +6,7 @@ module.exports = { moduleDirectories: ['packages', 'node_modules'], collectCoverage: true, coverageReporters: ['text'], - transformIgnorePatterns: ['node_modules/(?!' + ['superjson'].join('|') + ')'], + transformIgnorePatterns: [`node_modules/(?!${['superjson'].join('|')})`], transform: { '^.+\\.jsx?$': ['ts-jest', {useESM: true}] } diff --git a/package.json b/package.json index 014955c..e6146b4 100644 --- a/package.json +++ b/package.json @@ -56,11 +56,11 @@ "devDependencies": { "@commitlint/cli": "^17.4.1", "@commitlint/config-conventional": "^17.4.0", - "@rambler-tech/eslint-config": "^0.1.0", + "@rambler-tech/eslint-config": "^0.9.1", "@rambler-tech/licenselint": "^1.3.0", "@rambler-tech/licenselint-config": "^0.0.2", "@rambler-tech/prettier-config": "^0.1.0", - "@rambler-tech/ts-config": "^0.0.2", + "@rambler-tech/ts-config": "^0.1.0", "@rambler-tech/typedoc-config": "^0.3.0", "@size-limit/preset-small-lib": "^9.0.0", "@types/express": "^4.17.17", @@ -68,8 +68,8 @@ "@types/node": "^20.8.2", "@types/react": "^18.2.24", "@types/react-dom": "^18.2.8", - "eslint": "^8.31.0", - "eslint-config-prettier": "^9.0.0", + "eslint": "^8.56.0", + "eslint-config-prettier": "^9.1.0", "express": "^4.18.2", "history": "^5.3.0", "husky": "^8.0.3", diff --git a/src/client/index.ts b/src/client/index.ts index 4f3269c..7293c60 100644 --- a/src/client/index.ts +++ b/src/client/index.ts @@ -1,3 +1,4 @@ +/* eslint-disable import/no-unused-modules */ export {type DocumentProps, Document} from '../components/document' export {type LayoutProps, Layout} from '../components/layout' export {type ComponentFactory, lazy} from '../components/lazy' diff --git a/src/client/stream.tsx b/src/client/stream.tsx index 819ca21..1631f70 100644 --- a/src/client/stream.tsx +++ b/src/client/stream.tsx @@ -1,7 +1,7 @@ import React from 'react' import {hydrateRoot} from 'react-dom/client' import {BrowserRouter} from 'react-router-dom' -import {RenderOptions, TransitionMode} from '../common/types' +import {type RenderOptions, TransitionMode} from '../common/types' import {getState} from '../components/state' import {AppContextProvider} from '../components/context' import {matchRoute} from '../components/loader' @@ -45,6 +45,7 @@ export const hydrateFromStream = async ( ...rest } = options + // eslint-disable-next-line @arthurgeron/react-usememo/require-usememo const appContext = { ...state, ...rest diff --git a/src/common/json.ts b/src/common/json.ts index e7598f8..c7f0ac1 100644 --- a/src/common/json.ts +++ b/src/common/json.ts @@ -1,10 +1,4 @@ -import superjson from 'superjson' - -export const stringify = >(data: T): string => - escape(superjson.stringify(data)) - -export const parse = >(string: string): T => - superjson.parse(string) +import {parse as parseJson, stringify as stringifyJson} from 'superjson' /** * NOTE: @@ -13,12 +7,6 @@ export const parse = >(string: string): T => * More info: http://timelessrepo.com/json-isnt-a-javascript-subset */ -const escape = (value: string): string => value.replace(ESCAPE_REGEX, escaper) - -const escaper = (match: string): string => { - return ESCAPE_LOOKUP[match] -} - const ESCAPE_LOOKUP: Record = { '&': '\\u0026', '>': '\\u003e', @@ -28,3 +16,13 @@ const ESCAPE_LOOKUP: Record = { } const ESCAPE_REGEX = /[&><\u2028\u2029]/g + +const escape = (value: string): string => value.replace(ESCAPE_REGEX, escaper) + +const escaper = (match: string): string => ESCAPE_LOOKUP[match] + +export const stringify = >(data: T): string => + escape(stringifyJson(data)) + +export const parse = >(string: string): T => + parseJson(string) diff --git a/src/components/context.tsx b/src/components/context.tsx index b2d6022..66700fb 100644 --- a/src/components/context.tsx +++ b/src/components/context.tsx @@ -3,7 +3,7 @@ import type {Request, Response} from 'express' import type {InitialData, MetaData} from '../common/types' /** App context interface */ -export interface AppContextValue extends Record { +interface AppContextValue extends Record { /** Express.js [request](https://expressjs.com/en/4x/api.html#req) object (server-only) */ req?: Request /** Express [response](https://expressjs.com/en/4x/api.html#res) object (server-only) */ @@ -20,9 +20,9 @@ export interface AppContextValue extends Record { onChangeMetaData: (meta: MetaData) => void } -export const AppContext = createContext({} as AppContextValue) +const AppContext = createContext({} as AppContextValue) -export interface AppContextProviderProps { +interface AppContextProviderProps { value: Omit children: React.ReactNode } diff --git a/src/components/lazy.tsx b/src/components/lazy.tsx index 36ce9a8..d3b6e2b 100644 --- a/src/components/lazy.tsx +++ b/src/components/lazy.tsx @@ -9,7 +9,7 @@ import type { } from '../common/types' /** Page component factory */ -export interface ComponentModule { +interface ComponentModule { default: PageComponent } @@ -19,7 +19,7 @@ export interface ComponentFactory { } /** Data factory */ -export interface DataFactory { +interface DataFactory { (component: PageComponent, context: Context & C): ReturnType> } diff --git a/src/components/loader.test.tsx b/src/components/loader.test.tsx index 6014ff1..24508a2 100644 --- a/src/components/loader.test.tsx +++ b/src/components/loader.test.tsx @@ -1,5 +1,5 @@ -import {loadRouteData} from './loader' import {routes} from '../test/routes' +import {loadRouteData} from './loader' let context: any diff --git a/src/components/loader.tsx b/src/components/loader.tsx index 4d1ce1b..495349a 100644 --- a/src/components/loader.tsx +++ b/src/components/loader.tsx @@ -1,8 +1,8 @@ import {matchRoutes, type RouteMatch} from 'react-router-dom' -import {Context, PageRoute, InitialData, MetaData} from '../common/types' +import type {Context, PageRoute, InitialData, MetaData} from '../common/types' /** Match route options */ -export interface MatchRouteOptions { +interface MatchRouteOptions { pathname: string routes: PageRoute[] } @@ -18,12 +18,12 @@ export const matchRoute = ({ } /** Route loader options */ -export interface LoadRouteDataOptions extends MatchRouteOptions { +interface LoadRouteDataOptions extends MatchRouteOptions { context: Context } /** Route data */ -export interface RouteData { +interface RouteData { data?: InitialData meta?: MetaData match?: RouteMatch diff --git a/src/components/meta.tsx b/src/components/meta.tsx index 3e91eca..d5df01b 100644 --- a/src/components/meta.tsx +++ b/src/components/meta.tsx @@ -1,27 +1,6 @@ import React from 'react' import {useAppContext} from './context' -/** Default meta data component */ -export const Meta: React.FC = () => { - const {meta = {}} = useAppContext() - - return ( - <> - {Object.entries(meta).map(([name, content = '']) => - name === 'title' ? ( - {content} - ) : HEAD_LINKS_RELS.includes(name) ? ( - - ) : name.startsWith('og:') ? ( - - ) : ( - - ) - )} - - ) -} - const HEAD_LINKS_RELS = [ 'canonical', 'alternate', @@ -34,3 +13,28 @@ const HEAD_LINKS_RELS = [ 'preload', 'stylesheet' ] + +/** Default meta data component */ +export const Meta: React.FC = () => { + const {meta = {}} = useAppContext() + + return ( + <> + {Object.entries(meta).map(([name, content = '']) => { + if (name === 'title') { + return {content} + } + + if (HEAD_LINKS_RELS.includes(name)) { + return + } + + if (name.startsWith('og:')) { + return + } + + return + })} + + ) +} diff --git a/src/components/routes.tsx b/src/components/routes.tsx index bf41877..057186b 100644 --- a/src/components/routes.tsx +++ b/src/components/routes.tsx @@ -11,7 +11,7 @@ import {useAppContext} from './context' import {loadRouteData, matchRoute} from './loader' /** Routing props */ -export interface RoutesProps { +interface RoutesProps { routes: PageRoute[] scrollToTop?: boolean transition?: TransitionMode @@ -46,7 +46,7 @@ export const Routes: React.FC = ({ const isBlockedMode = !isWaitingMode && transition !== TransitionMode.INSTANT useEffect(() => { - if (location !== currentLocation) { + const onNavigate = async (): Promise => { const {pathname} = location const context = { @@ -57,26 +57,30 @@ export const Routes: React.FC = ({ ...rest } - setRouteData((prevState) => ({...prevState, isLoading: true})) + setRouteData((previousState) => ({...previousState, isLoading: true})) if (scrollToTop && !isBlockedMode) { window.scrollTo(0, 0) } - loadRouteData({pathname, routes, context}).then((routeData) => { - if (scrollToTop && isBlockedMode) { - window.scrollTo(0, 0) - } + const routeData = await loadRouteData({pathname, routes, context}) + + if (scrollToTop && isBlockedMode) { + window.scrollTo(0, 0) + } - setRouteData((prevState) => ({ - ...prevState, - ...routeData, - isLoading: false - })) + setRouteData((previousState) => ({ + ...previousState, + ...routeData, + isLoading: false + })) - setCurrentLocation(location) - onChangeMetaData?.(routeData.meta ?? {}) - }) + setCurrentLocation(location) + onChangeMetaData?.(routeData.meta ?? {}) + } + + if (location !== currentLocation) { + onNavigate() } }, [location, currentLocation, scrollToTop]) // eslint-disable-line react-hooks/exhaustive-deps diff --git a/src/components/scripts.tsx b/src/components/scripts.tsx index 67f60ff..e4dbad9 100644 --- a/src/components/scripts.tsx +++ b/src/components/scripts.tsx @@ -5,5 +5,7 @@ import {useAppContext} from './context' export const Scripts: React.FC = () => { const {scripts} = useAppContext() - return <>{scripts?.map((src) =>