1
0
mirror of https://github.com/ellmau/adf-obdd.git synced 2025-12-20 09:39:38 +01:00

Add basic UI for user endpoints

This commit is contained in:
monsterkrampe 2023-04-03 17:33:48 +02:00
parent e353e01c1d
commit 257bd5cdfc
No known key found for this signature in database
GPG Key ID: B8ADC1F5A5CE5057
9 changed files with 485 additions and 122 deletions

View File

@ -5,7 +5,8 @@ module.exports = {
},
"extends": [
"plugin:react/recommended",
"airbnb"
"airbnb",
"airbnb-typescript",
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
@ -13,7 +14,8 @@ module.exports = {
"jsx": true
},
"ecmaVersion": "latest",
"sourceType": "module"
"sourceType": "module",
"project": "tsconfig.json"
},
"plugins": [
"react",

View File

@ -4,16 +4,19 @@
"source": "src/index.html",
"browserslist": "> 0.5%, last 2 versions, not dead",
"scripts": {
"check": "tsc --noEmit && eslint ./src",
"start": "parcel",
"build": "parcel build"
},
"devDependencies": {
"@types/node": "^18.15.11",
"@types/react": "^18.0.26",
"@types/react-dom": "^18.0.10",
"@typescript-eslint/eslint-plugin": "^5.48.1",
"@typescript-eslint/parser": "^5.48.1",
"eslint": "^8.31.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-airbnb-typescript": "^17.0.0",
"eslint-plugin-import": "^2.27.4",
"eslint-plugin-jsx-a11y": "^6.7.1",
"eslint-plugin-react": "^7.32.0",

View File

@ -6,8 +6,8 @@ import '@fontsource/roboto/400.css';
import '@fontsource/roboto/500.css';
import '@fontsource/roboto/700.css';
import App from './components/app.tsx';
import App from './components/app';
const container = document.getElementById('app');
const root = createRoot(container);
const root = createRoot(container!);
root.render(<App />);

View File

@ -19,9 +19,11 @@ import {
TextField,
} from '@mui/material';
import GraphG6 from './graph-g6.tsx';
import LoadingContext from './loading-context';
import GraphG6, { GraphProps } from './graph-g6';
import Footer from './footer';
const { useState, useCallback } = React;
const { useState, useCallback, useMemo } = React;
const darkTheme = createTheme({
palette: {
@ -57,7 +59,7 @@ function App() {
const [loading, setLoading] = useState(false);
const [code, setCode] = useState(placeholder);
const [parsing, setParsing] = useState(Parsing.Naive);
const [graphs, setGraphs] = useState();
const [graphs, setGraphs] = useState<GraphProps[]>();
const [graphIndex, setGraphIndex] = useState(0);
const submitHandler = useCallback(
@ -82,93 +84,98 @@ function App() {
[code, parsing],
);
const loadingContext = useMemo(() => ({ loading, setLoading }), [loading, setLoading]);
return (
<ThemeProvider theme={darkTheme}>
<CssBaseline />
<main>
<Typography variant="h2" component="h1" align="center" gutterBottom>
Solve your ADF Problem with OBDDs!
</Typography>
<LoadingContext.Provider value={loadingContext}>
<CssBaseline />
<main>
<Typography variant="h2" component="h1" align="center" gutterBottom>
Solve your ADF Problem with OBDDs!
</Typography>
<Container>
<TextField
name="code"
label="Put your code here:"
helperText={(
<Container>
<TextField
name="code"
label="Put your code here:"
helperText={(
<>
For more info on the syntax, have a
look
{' '}
<Link href="https://github.com/ellmau/adf-obdd" target="_blank" rel="noreferrer">here</Link>
.
</>
)}
multiline
fullWidth
variant="filled"
value={code}
onChange={(event) => { setCode(event.target.value); }}
/>
</Container>
<Container sx={{ marginTop: 2, marginBottom: 2 }}>
<FormControl>
<FormLabel id="parsing-radio-group">Parsing Strategy</FormLabel>
<RadioGroup
row
aria-labelledby="parsing-radio-group"
name="parsing"
value={parsing}
onChange={(e) => setParsing(((e.target as HTMLInputElement).value) as Parsing)}
>
<FormControlLabel value={Parsing.Naive} control={<Radio />} label="Naive" />
<FormControlLabel value={Parsing.Hybrid} control={<Radio />} label="Hybrid" />
</RadioGroup>
</FormControl>
<br />
<br />
<Button variant="outlined" onClick={() => submitHandler(Strategy.ParseOnly)}>Parse only</Button>
{' '}
<Button variant="outlined" onClick={() => submitHandler(Strategy.Ground)}>Grounded Model</Button>
{' '}
<Button variant="outlined" onClick={() => submitHandler(Strategy.Complete)}>Complete Models</Button>
{' '}
<Button variant="outlined" onClick={() => submitHandler(Strategy.Stable)}>Stable Models (naive heuristics)</Button>
{' '}
<Button disabled={parsing !== Parsing.Hybrid} variant="outlined" onClick={() => submitHandler(Strategy.StableCountingA)}>Stable Models (counting heuristic A)</Button>
{' '}
<Button disabled={parsing !== Parsing.Hybrid} variant="outlined" onClick={() => submitHandler(Strategy.StableCountingB)}>Stable Models (counting heuristic B)</Button>
{' '}
<Button variant="outlined" onClick={() => submitHandler(Strategy.StableNogood)}>Stable Models using nogoods (Simple Heuristic)</Button>
</Container>
{graphs
&& (
<Container sx={{ marginTop: 4, marginBottom: 4 }}>
{graphs.length > 1
&& (
<>
For more info on the syntax, have a
look
{' '}
<Link href="https://github.com/ellmau/adf-obdd" target="_blank" rel="noreferrer">here</Link>
.
Models:
<br />
<Pagination variant="outlined" shape="rounded" count={graphs.length} page={graphIndex + 1} onChange={(e, value) => setGraphIndex(value - 1)} />
</>
)}
multiline
fullWidth
variant="filled"
value={code}
onChange={(event) => { setCode(event.target.value); }}
/>
</Container>
<Container sx={{ marginTop: 2, marginBottom: 2 }}>
<FormControl>
<FormLabel id="parsing-radio-group">Parsing Strategy</FormLabel>
<RadioGroup
row
aria-labelledby="parsing-radio-group"
name="parsing"
value={parsing}
onChange={(e) => setParsing((e.target as HTMLInputElement).value)}
>
<FormControlLabel value={Parsing.Naive} control={<Radio />} label="Naive" />
<FormControlLabel value={Parsing.Hybrid} control={<Radio />} label="Hybrid" />
</RadioGroup>
</FormControl>
<br />
<br />
<Button variant="outlined" onClick={() => submitHandler(Strategy.ParseOnly)}>Parse only</Button>
{' '}
<Button variant="outlined" onClick={() => submitHandler(Strategy.Ground)}>Grounded Model</Button>
{' '}
<Button variant="outlined" onClick={() => submitHandler(Strategy.Complete)}>Complete Models</Button>
{' '}
<Button variant="outlined" onClick={() => submitHandler(Strategy.Stable)}>Stable Models (naive heuristics)</Button>
{' '}
<Button disabled={parsing !== Parsing.Hybrid} variant="outlined" onClick={() => submitHandler(Strategy.StableCountingA)}>Stable Models (counting heuristic A)</Button>
{' '}
<Button disabled={parsing !== Parsing.Hybrid} variant="outlined" onClick={() => submitHandler(Strategy.StableCountingB)}>Stable Models (counting heuristic B)</Button>
{' '}
<Button variant="outlined" onClick={() => submitHandler(Strategy.StableNogood)}>Stable Models using nogoods (Simple Heuristic)</Button>
</Container>
)}
{graphs.length > 0
&& (
<Paper elevation={3} square sx={{ marginTop: 4, marginBottom: 4 }}>
<GraphG6 graph={graphs[graphIndex]} />
</Paper>
)}
{graphs.length === 0
&& <>No models!</>}
</Container>
)}
</main>
<Footer />
{graphs
&& (
<Container sx={{ marginTop: 4, marginBottom: 4 }}>
{graphs.length > 1
&& (
<>
Models:
<br />
<Pagination variant="outlined" shape="rounded" count={graphs.length} page={graphIndex + 1} onChange={(e, value) => setGraphIndex(value - 1)} />
</>
)}
{graphs.length > 0
&& (
<Paper elevation={3} square sx={{ marginTop: 4, marginBottom: 4 }}>
<GraphG6 graph={graphs[graphIndex]} />
</Paper>
)}
{graphs.length === 0
&& <>No models!</>}
</Container>
)}
</main>
<Backdrop
open={loading}
>
<CircularProgress color="inherit" />
</Backdrop>
<Backdrop
open={loading}
>
<CircularProgress color="inherit" />
</Backdrop>
</LoadingContext.Provider>
</ThemeProvider>
);
}

View File

@ -0,0 +1,220 @@
import React, {
useState, useCallback, useContext, useEffect,
} from 'react';
import {
Alert,
AppBar,
Button,
Dialog,
DialogActions,
DialogContent,
DialogTitle,
Snackbar,
TextField,
Toolbar,
} from '@mui/material';
import LoadingContext from './loading-context';
enum UserFormType {
Login = 'Login',
Register = 'Register',
Update = 'Update',
}
interface UserFormProps {
formType: UserFormType | null;
close: (message?: string) => void;
username?: string;
}
function UserForm({ username: propUsername, formType, close }: UserFormProps) {
const { setLoading } = useContext(LoadingContext);
const [username, setUsername] = useState<string>(propUsername || '');
const [password, setPassword] = useState<string>('');
const [errorOccurred, setError] = useState<boolean>(false);
const submitHandler = useCallback(
(del: boolean) => {
setLoading(true);
setError(false);
let method; let
endpoint;
if (del) {
method = 'DELETE';
endpoint = '/users/delete';
} else {
switch (formType) {
case UserFormType.Login:
method = 'POST';
endpoint = '/users/login';
break;
case UserFormType.Register:
method = 'POST';
endpoint = '/users/register';
break;
case UserFormType.Update:
method = 'PUT';
endpoint = '/users/update';
break;
default:
// NOTE: the value is not null when the dialog is open
break;
}
}
fetch(`${process.env.NODE_ENV === 'development' ? '//localhost:8080' : ''}${endpoint}`, {
method,
credentials: process.env.NODE_ENV === 'development' ? 'include' : 'same-origin',
headers: {
'Content-Type': 'application/json',
},
body: !del ? JSON.stringify({ username, password }) : undefined,
})
.then((res) => {
switch (res.status) {
case 200:
close(`Action '${formType}' successful!`);
break;
default:
setError(true);
break;
}
})
.finally(() => setLoading(false));
},
[username, password, formType],
);
return (
<>
<DialogTitle>{formType}</DialogTitle>
<DialogContent>
<TextField variant="standard" type="text" label="Username" value={username} onChange={(event) => { setUsername(event.target.value); }} />
<br />
<TextField variant="standard" type="password" label="Password" value={password} onChange={(event) => { setPassword(event.target.value); }} />
{errorOccurred
&& <Alert severity="error">Check your inputs!</Alert>}
</DialogContent>
<DialogActions>
<Button onClick={() => close()}>Cancel</Button>
<Button onClick={() => submitHandler(false)}>{formType}</Button>
{formType === UserFormType.Update
// TODO: add another confirm dialog here
&& (
<Button
variant="outlined"
onClick={() => {
// eslint-disable-next-line no-alert
if (window.confirm('Are you sure that you want to delete your account?')) {
submitHandler(true);
}
}}
>
Delete Account
</Button>
)}
</DialogActions>
</>
);
}
UserForm.defaultProps = { username: undefined };
function Footer() {
const [username, setUsername] = useState<string>();
const [tempUser, setTempUser] = useState<boolean>();
const [dialogTypeOpen, setDialogTypeOpen] = useState<UserFormType | null>(null);
const [snackbarMessage, setSnackbarMessage] = useState<string | undefined>();
const logout = useCallback(() => {
fetch(`${process.env.NODE_ENV === 'development' ? '//localhost:8080' : ''}/users/logout`, {
method: 'DELETE',
credentials: process.env.NODE_ENV === 'development' ? 'include' : 'same-origin',
headers: {
'Content-Type': 'application/json',
},
})
.then((res) => {
switch (res.status) {
case 200:
setSnackbarMessage('Logout successful!');
setUsername(undefined);
break;
default:
setSnackbarMessage('An error occurred while trying to log out.');
break;
}
});
}, [setSnackbarMessage]);
useEffect(() => {
// Intuition: If the dialog was just closed (or on first render).
if (!dialogTypeOpen) {
fetch(`${process.env.NODE_ENV === 'development' ? '//localhost:8080' : ''}/users/info`, {
method: 'GET',
credentials: process.env.NODE_ENV === 'development' ? 'include' : 'same-origin',
headers: {
'Content-Type': 'application/json',
},
})
.then((res) => {
switch (res.status) {
case 200:
res.json().then(({ username: user, temp }) => {
setUsername(user);
setTempUser(temp);
});
break;
default:
setUsername(undefined);
break;
}
});
}
}, [dialogTypeOpen]);
return (
<>
<AppBar position="fixed" sx={{ top: 'auto', bottom: 0 }}>
<Toolbar sx={{ justifyContent: 'center' }}>
{username ? (
<>
<span>
Logged in as:
{' '}
{username}
{' '}
{tempUser ? '(Temporary User. Edit to set a password!)' : undefined}
</span>
<Button color="inherit" onClick={() => setDialogTypeOpen(UserFormType.Update)}>Edit</Button>
{!tempUser && <Button color="inherit" onClick={() => logout()}>Logout</Button>}
</>
) : (
<>
<Button color="inherit" onClick={() => setDialogTypeOpen(UserFormType.Login)}>Login</Button>
<Button color="inherit" onClick={() => setDialogTypeOpen(UserFormType.Register)}>Register</Button>
</>
)}
</Toolbar>
</AppBar>
<Dialog open={!!dialogTypeOpen} onClose={() => setDialogTypeOpen(null)}>
<UserForm
formType={dialogTypeOpen}
close={(message) => { setDialogTypeOpen(null); setSnackbarMessage(message); }}
username={dialogTypeOpen === UserFormType.Update ? username : undefined}
/>
</Dialog>
<Snackbar
open={!!snackbarMessage}
autoHideDuration={5000}
message={snackbarMessage}
onClose={() => setSnackbarMessage(undefined)}
/>
</>
);
}
export default Footer;

View File

@ -1,13 +1,13 @@
import React, { useEffect, useRef } from 'react';
import G6 from '@antv/g6';
import G6, { Graph } from '@antv/g6';
G6.registerNode('nodeWithFlag', {
draw(cfg, group) {
const mainWidth = Math.max(30, 5 * cfg.mainLabel.length + 10);
const mainWidth = Math.max(30, 5 * (cfg!.mainLabel as string).length + 10);
const mainHeight = 30;
const keyShape = group.addShape('rect', {
const keyShape = group!.addShape('rect', {
attrs: {
width: mainWidth,
height: mainHeight,
@ -20,13 +20,13 @@ G6.registerNode('nodeWithFlag', {
draggable: true,
});
group.addShape('text', {
group!.addShape('text', {
attrs: {
x: mainWidth / 2,
y: mainHeight / 2,
textAlign: 'center',
textBaseline: 'middle',
text: cfg.mainLabel,
text: cfg!.mainLabel,
fill: '#212121',
fontFamily: 'Roboto',
cursor: 'pointer',
@ -37,14 +37,14 @@ G6.registerNode('nodeWithFlag', {
draggable: true,
});
if (cfg.subLabel) {
const subWidth = 5 * cfg.subLabel.length + 4;
if (cfg!.subLabel) {
const subWidth = 5 * (cfg!.subLabel as string).length + 4;
const subHeight = 20;
const subRectX = mainWidth - 4;
const subRectY = -subHeight + 4;
group.addShape('rect', {
group!.addShape('rect', {
attrs: {
x: subRectX,
y: subRectY,
@ -59,13 +59,13 @@ G6.registerNode('nodeWithFlag', {
draggable: true,
});
group.addShape('text', {
group!.addShape('text', {
attrs: {
x: subRectX + subWidth / 2,
y: subRectY + subHeight / 2,
textAlign: 'center',
textBaseline: 'middle',
text: cfg.subLabel,
text: cfg!.subLabel,
fill: '#212121',
fontFamily: 'Roboto',
fontSize: 10,
@ -95,6 +95,7 @@ G6.registerNode('nodeWithFlag', {
// },
// },
setState(name, value, item) {
if (!item) { return; }
const group = item.getContainer();
const mainShape = group.get('children')[0]; // Find the first graphics shape of the node. It is determined by the order of being added
const subShape = group.get('children')[2];
@ -131,11 +132,11 @@ G6.registerNode('nodeWithFlag', {
},
});
interface GraphProps {
lo_edges: [number, number][],
hi_edges: [number, number][],
node_labels: { [key: number]: string },
tree_root_labels: { [key: number]: string[] },
export interface GraphProps {
lo_edges: [string, string][],
hi_edges: [string, string][],
node_labels: { [key: string]: string },
tree_root_labels: { [key: string]: string[] },
}
function nodesAndEdgesFromGraphProps(graphProps: GraphProps) {
@ -174,24 +175,26 @@ function GraphG6(props: Props) {
const ref = useRef(null);
const graphRef = useRef();
const graphRef = useRef<Graph>();
useEffect(
() => {
if (!graphRef.current) {
graphRef.current = new G6.Graph({
container: ref.current,
graphRef.current = new Graph({
container: ref.current!,
width: 1200,
height: 600,
fitView: true,
rankdir: 'TB',
align: 'DR',
nodesep: 100,
ranksep: 100,
modes: {
default: ['drag-canvas', 'zoom-canvas', 'drag-node'],
},
layout: { type: 'dagre' },
layout: {
type: 'dagre',
rankdir: 'TB',
align: 'DR',
nodesep: 100,
ranksep: 100,
},
// defaultNode: {
// anchorPoints: [[0.5, 0], [0, 0.5], [1, 0.5], [0.5, 1]],
// type: 'rect',
@ -239,13 +242,13 @@ function GraphG6(props: Props) {
// Mouse enter a node
graph.on('node:mouseenter', (e) => {
const nodeItem = e.item; // Get the target item
const nodeItem = e.item!; // Get the target item
graph.setItemState(nodeItem, 'hover', true); // Set the state 'hover' of the item to be true
});
// Mouse leave a node
graph.on('node:mouseleave', (e) => {
const nodeItem = e.item; // Get the target item
const nodeItem = e.item!; // Get the target item
graph.setItemState(nodeItem, 'hover', false); // Set the state 'hover' of the item to be false
});
},
@ -254,11 +257,11 @@ function GraphG6(props: Props) {
useEffect(
() => {
const graph = graphRef.current;
const graph = graphRef.current!;
// Click a node
graph.on('node:click', (e) => {
const nodeItem = e.item; // et the clicked item
const nodeItem = e.item!; // et the clicked item
let onlyRemoveStates = false;
if (nodeItem.hasState('highlight')) {
@ -290,12 +293,12 @@ function GraphG6(props: Props) {
graph.setItemState(edge, 'lowlight', true);
});
const relevantNodeIds = [];
const relevantLoEdges = [];
const relevantHiEdges = [];
let newNodeIds = [nodeItem.getModel().id];
let newLoEdges = [];
let newHiEdges = [];
const relevantNodeIds: string[] = [];
const relevantLoEdges: [string, string][] = [];
const relevantHiEdges: [string, string][] = [];
let newNodeIds: string[] = [nodeItem.getModel().id!];
let newLoEdges: [string, string][] = [];
let newHiEdges: [string, string][] = [];
while (newNodeIds.length > 0 || newLoEdges.length > 0 || newHiEdges.length > 0) {
relevantNodeIds.push(...newNodeIds);
@ -347,7 +350,7 @@ function GraphG6(props: Props) {
useEffect(
() => {
const graph = graphRef.current;
const graph = graphRef.current!;
const { nodes, edges } = nodesAndEdgesFromGraphProps(graphProps);

View File

@ -0,0 +1,13 @@
import { createContext } from 'react';
interface ILoadingContext {
loading: boolean;
setLoading: (loading: boolean) => void;
}
const LoadingContext = createContext<ILoadingContext>({
loading: false,
setLoading: () => {},
});
export default LoadingContext;

103
frontend/tsconfig.json Normal file
View File

@ -0,0 +1,103 @@
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig to read more about this file */
/* Projects */
// "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */
// "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */
// "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */
// "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */
// "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */
// "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */
/* Language and Environment */
"target": "es2016", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */
// "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */
"jsx": "preserve", /* Specify what JSX code is generated. */
// "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */
// "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */
// "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */
// "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */
// "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */
// "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */
// "noLib": true, /* Disable including any library files, including the default lib.d.ts. */
// "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */
// "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */
/* Modules */
"module": "commonjs", /* Specify what module code is generated. */
// "rootDir": "./", /* Specify the root folder within your source files. */
// "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */
// "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */
// "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */
// "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */
// "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */
// "types": [], /* Specify type package names to be included without being referenced in a source file. */
// "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */
// "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */
// "resolveJsonModule": true, /* Enable importing .json files. */
// "noResolve": true, /* Disallow 'import's, 'require's or '<reference>'s from expanding the number of files TypeScript should add to a project. */
/* JavaScript Support */
// "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */
// "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */
// "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */
/* Emit */
// "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */
// "declarationMap": true, /* Create sourcemaps for d.ts files. */
// "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */
// "sourceMap": true, /* Create source map files for emitted JavaScript files. */
// "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */
// "outDir": "./", /* Specify an output folder for all emitted files. */
// "removeComments": true, /* Disable emitting comments. */
// "noEmit": true, /* Disable emitting files from a compilation. */
// "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */
// "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */
// "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */
// "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
// "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */
// "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */
// "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */
// "newLine": "crlf", /* Set the newline character for emitting files. */
// "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */
// "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */
// "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */
// "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */
// "declarationDir": "./", /* Specify the output directory for generated declaration files. */
// "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */
/* Interop Constraints */
// "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */
// "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */
"esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */
// "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */
"forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */
/* Type Checking */
"strict": true, /* Enable all strict type-checking options. */
// "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */
// "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */
// "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */
// "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */
// "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */
// "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */
// "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */
// "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */
// "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */
// "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */
// "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */
// "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */
// "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */
// "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */
// "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */
// "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */
// "allowUnusedLabels": true, /* Disable error reporting for unused labels. */
// "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */
/* Completeness */
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
}
}

View File

@ -1323,6 +1323,11 @@
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
"@types/node@^18.15.11":
version "18.15.11"
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.11.tgz#b3b790f09cb1696cffcec605de025b088fa4225f"
integrity sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==
"@types/parse-json@^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
@ -2204,6 +2209,13 @@ eslint-config-airbnb-base@^15.0.0:
object.entries "^1.1.5"
semver "^6.3.0"
eslint-config-airbnb-typescript@^17.0.0:
version "17.0.0"
resolved "https://registry.yarnpkg.com/eslint-config-airbnb-typescript/-/eslint-config-airbnb-typescript-17.0.0.tgz#360dbcf810b26bbcf2ff716198465775f1c49a07"
integrity sha512-elNiuzD0kPAPTXjFWg+lE24nMdHMtuxgYoD30OyMD6yrW1AhFZPAg27VX7d3tzOErw+dgJTNWfRSDqEcXb4V0g==
dependencies:
eslint-config-airbnb-base "^15.0.0"
eslint-config-airbnb@^19.0.4:
version "19.0.4"
resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-19.0.4.tgz#84d4c3490ad70a0ffa571138ebcdea6ab085fdc3"