Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update react-scripts and Typescript to version 4 #85

Merged
merged 13 commits into from
Feb 15, 2021
9 changes: 0 additions & 9 deletions .eslintrc.json

This file was deleted.

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
.env.development.local
.env.test.local
.env.production.local
.eslintcache

npm-debug.log*
yarn-debug.log*
Expand Down
18,057 changes: 9,783 additions & 8,274 deletions package-lock.json

Large diffs are not rendered by default.

21 changes: 15 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"coverageReporters": [
"text",
"lcov"
]
],
"resetMocks": false
},
"dependencies": {
"@babel/cli": "^7.10.1",
Expand All @@ -29,7 +30,7 @@
"@types/react-dom": "^16.9.5",
"@types/react-helmet": "^6.0.0",
"@types/react-router-config": "^5.0.1",
"@types/react-router-dom": "^5.1.3",
"@types/react-router-dom": "^5.1.7",
"axios": "^0.21.1",
"babel-plugin-transform-assets": "^1.0.2",
"bootstrap": "^4.5.0",
Expand All @@ -50,12 +51,12 @@
"react-helmet": "^6.0.0",
"react-hook-form": "^5.6.1",
"react-router-dom": "^5.1.2",
"react-scripts": "^3.4.3",
"react-scripts": "^4.0.1",
"serialize-javascript": "^3.1.0",
"slate": "^0.58.3",
"slate-history": "^0.58.4",
"slate-react": "^0.58.4",
"typescript": "~3.9.7"
"typescript": "^4.1.3"
},
"scripts": {
"start": "react-scripts start",
Expand All @@ -67,7 +68,16 @@
"size": "npm run build && size-limit"
},
"eslintConfig": {
"extends": "react-app"
"extends": [
"react-app",
"prettier"
],
"parserOptions": {
"ecmaVersion": 2018
},
"env": {
"es2017": true
}
},
"browserslist": {
"production": [
Expand All @@ -94,7 +104,6 @@
"@types/scheduler": "^0.16.1",
"@types/serialize-javascript": "^1.5.0",
"core-js": "^3.6.5",
"eslint": "^6.8.0",
"eslint-config-prettier": "^6.10.0",
"glob": "^7.1.6",
"jest-mock-axios": "^4.0.0",
Expand Down
8 changes: 2 additions & 6 deletions scripts/generate-manifest.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
const fs = require("fs");
const path = require("path");

const configPath = path.resolve(__dirname, "..", "src", "config.ts");
const configPath = path.resolve(__dirname, "..", "src", "config", "config.json");
const manifestPath = path.resolve(
__dirname,
"..",
Expand All @@ -21,11 +21,7 @@ console.log("Loading config from", configPath);

// Because TypeScript uses ES6 modules, we can't exactly load the contents of the config file
// So instead, we read the source and evaluate it.
const config = Function(
`"use strict"; return ${fs
.readFileSync(configPath, "utf-8")
.replace("export default", "")}`
)();
const config = JSON.parse(fs.readFileSync(configPath, "utf-8"))

console.log("Loaded config:");
console.dir(config);
Expand Down
5 changes: 3 additions & 2 deletions src/auth/__tests__/Auth.unit.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { User } from "../../shared/types";
import { testAdmin, testUser } from "../../shared/test-utils";
import { authReducer, CSRF_COOKIE } from "../Auth";
import Cookies from "js-cookie";

describe("authReducer", () => {
let authState: { user: User | null; csrfToken: string | null };

beforeAll(() => {
window.document.cookie = `${CSRF_COOKIE}=csrf`;
Cookies.set(CSRF_COOKIE, 'csrf')
});

beforeEach(() => {
Expand All @@ -22,7 +23,7 @@ describe("authReducer", () => {
});

afterAll(() => {
delete window.document.cookie;
Cookies.remove(CSRF_COOKIE)
});

describe("action:login", () => {
Expand Down
5 changes: 3 additions & 2 deletions src/auth/__tests__/AuthProvider.unit.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,14 @@ import { APIResponseFailure, APIError } from "../../shared/types";

// for spies
import * as _a from "../Auth";
import Cookies from "js-cookie";

describe("AuthProvider", () => {
let result: HookResult<AuthContext>;
let auth: AuthContext;

beforeAll(() => {
window.document.cookie = `${CSRF_COOKIE}=csrf`;
Cookies.set(CSRF_COOKIE, 'csrf')
});

beforeEach(() => {
Expand All @@ -36,7 +37,7 @@ describe("AuthProvider", () => {
});

afterAll(() => {
delete window.document.cookie;
Cookies.remove(CSRF_COOKIE)
});

it("provides access to all fields in interface (sanity check)", () => {
Expand Down
39 changes: 0 additions & 39 deletions src/config.ts

This file was deleted.

39 changes: 39 additions & 0 deletions src/config/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"baseurl": "http://mathnews.uwaterloo.ca",
"title": "mathNEWS",
"description": "UWaterloo's Bastion of Erudite Thought",
"themeColor": "#000000",
"locale": "en_CA",
"alternateLocales": [],
"icons": {
"favicon": {
"src": "favicon.ico",
"type": "image/x-icon",
"sizes": "64x64 32x32 16x16"
},
"touchIcon": {
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
"largeIcon": {
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
},
"seo": {
"image": "",
"twitter": {
"card": "summary_large_image",
"site": "@UWmathNEWS"
}
},
"manifest": {
"fullName": "",
"start_url": ".",
"display": "standalone",
"backgroundColor": "#ffffff"
},
"googleSiteVerification": ""
}
2 changes: 2 additions & 0 deletions src/config/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import config from "./config.json";
export default config;
6 changes: 5 additions & 1 deletion src/dash/EditorPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,14 @@ const getEditorRequestState = (
}
};

interface EditorPageRouteParams {
articleId: string
}

const ARTICLE_SAVE_DELAY_MSECS = 10000;

const EditorPage: React.FC<RouteComponentProps> = (props) => {
const { articleId } = useParams();
const { articleId } = useParams<EditorPageRouteParams>();

const [lastSaved, setLastSaved] = useState<Date>(new Date());

Expand Down
6 changes: 5 additions & 1 deletion src/dash/issues/DashIssueDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,12 @@ const columns: Column<Article>[] = [
},
];

interface DashIssueDetailRouteParams {
issueId: string
}

const DashIssueDetail: React.FC<RouteComponentProps> = (props) => {
const { issueId } = useParams();
const { issueId } = useParams<DashIssueDetailRouteParams>();

const [issue, issueError, issueReqInfo] = useAPI(
useCallback(() => {
Expand Down
5 changes: 1 addition & 4 deletions src/shared/components/ActionLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,8 @@ import type { LinkProps } from "react-router-dom";
const ActionLink = React.forwardRef<HTMLAnchorElement, LinkProps>(
({ className, children, ...props }, ref) => {
return (
// Link forwards its refs (see
// https://github.com/ReactTraining/react-router/blob/master/packages/react-router-dom/docs/api/Link.md#innerref-refobject)
// but this is not recognized by the provided typings, so we must bodge it with a cast
<Link
ref={ref as React.Ref<Link>}
ref={ref}
className={`ActionLink ${className || ""}`}
{...props}
>
Expand Down
2 changes: 1 addition & 1 deletion src/shared/components/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ export const LinkButton = React.forwardRef<
>(({ variant, className, children, ...props }, ref) => {
return (
<Link
ref={ref as React.Ref<Link>}
ref={ref}
{...(props as LinkProps)}
className={`btn btn-primary Button Button-${variant} ${className || ""}`}
>
Expand Down
4 changes: 3 additions & 1 deletion src/shared/components/Loader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ interface LoaderProps {
hideFromScreenreaders?: boolean;
}

export default (props: LoaderProps) => {
const Loader: React.FC<LoaderProps> = (props: LoaderProps) => {
if (props.variant === "spinner") {
return (
<div className={`d-flex justify-content-center ${props.className}`}>
Expand All @@ -32,3 +32,5 @@ export default (props: LoaderProps) => {
}
return <></>;
};

export default Loader;
8 changes: 4 additions & 4 deletions src/shared/contexts/ToastContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export interface ToastManager {
addToasts: (toasts: ToastMessage[]) => void;
}

const ToastManager = createContext<ToastManager>({
const ToastManagerContext = createContext<ToastManager>({
toasts: [],
setToasts: () => {},
setToastsHeuristically: () => {},
Expand Down Expand Up @@ -67,10 +67,10 @@ export const ToastProvider: React.FC = props => {
}).filter(t => t._delay === undefined || t._delay > 100))); // 150ms is the default bootstrap anim duration

return (
<ToastManager.Provider value={{ toasts, setToasts, setToastsHeuristically, addToasts }}>
<ToastManagerContext.Provider value={{ toasts, setToasts, setToastsHeuristically, addToasts }}>
{props.children}
</ToastManager.Provider>
</ToastManagerContext.Provider>
)
};

export const useToast = () => useContext(ToastManager);
export const useToast = () => useContext(ToastManagerContext);
5 changes: 5 additions & 0 deletions src/shared/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ const errorsProxyFactory = (errors: { [key: string]: any }): ErrorsProxy => {
return new Proxy(proxiedErrors, {
get(_, prop: string) {
if (prop === "__typeof__") return "proxy";
// HACK: react-refresh scans every export and uses $$typeof to determine
// if it's a React component that it needs to process. Without this, we'll
// throw an error here which breaks initialization.
// TODO: Consider returning undefined instead of throwing an error in the "not found" case.
if (prop === "$$typeof") return undefined;
if (prop.includes(" ")) return prop;
if (prop in memo) return memo[prop];

Expand Down
5 changes: 3 additions & 2 deletions src/shared/form/PasswordField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ export const validatePassword = {
const PasswordField = React.forwardRef<
FormControlElementType,
PasswordFieldProps<any>
>(({ state = useState<boolean>(false), context, ...props }, ref) => {
const [showPassword, setShowPassword] = state;
>(({ state, context, ...props }, ref) => {
const defaultState = useState<boolean>(false)
const [showPassword, setShowPassword] = state ?? defaultState;
return (
<Field
type={showPassword ? "text" : "password"}
Expand Down
15 changes: 11 additions & 4 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
Expand All @@ -13,8 +17,11 @@
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react",
"downlevelIteration": true
"jsx": "react-jsx",
"downlevelIteration": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"]
"include": [
"src"
]
}