Merge branch 'develop' into Umur-reducer-dev
This commit is contained in:
commit
2dc204e222
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
|
@ -154,5 +154,7 @@ jobs:
|
||||||
run: cd ../../ && yarn
|
run: cd ../../ && yarn
|
||||||
- name: Build rescript in squiggle-lang
|
- name: Build rescript in squiggle-lang
|
||||||
run: cd ../squiggle-lang && yarn build
|
run: cd ../squiggle-lang && yarn build
|
||||||
|
- name: Build components
|
||||||
|
run: cd ../components && yarn build
|
||||||
- name: Build website assets
|
- name: Build website assets
|
||||||
run: yarn build
|
run: yarn build
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@headlessui/react": "^1.6.4",
|
"@headlessui/react": "^1.6.4",
|
||||||
"@heroicons/react": "^1.0.6",
|
"@heroicons/react": "^1.0.6",
|
||||||
"@hookform/resolvers": "^2.8.10",
|
"@hookform/resolvers": "^2.9.0",
|
||||||
"@quri/squiggle-lang": "^0.2.8",
|
"@quri/squiggle-lang": "^0.2.8",
|
||||||
"@react-hook/size": "^2.1.2",
|
"@react-hook/size": "^2.1.2",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
|
@ -22,40 +22,42 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/plugin-proposal-private-property-in-object": "^7.17.12",
|
"@babel/plugin-proposal-private-property-in-object": "^7.17.12",
|
||||||
"@storybook/addon-actions": "^6.5.6",
|
"@storybook/addon-actions": "^6.5.7",
|
||||||
"@storybook/addon-essentials": "^6.5.6",
|
"@storybook/addon-essentials": "^6.5.7",
|
||||||
"@storybook/addon-links": "^6.5.6",
|
"@storybook/addon-links": "^6.5.7",
|
||||||
"@storybook/builder-webpack5": "^6.5.6",
|
"@storybook/builder-webpack5": "^6.5.7",
|
||||||
"@storybook/manager-webpack5": "^6.5.6",
|
"@storybook/manager-webpack5": "^6.5.7",
|
||||||
"@storybook/node-logger": "^6.5.6",
|
"@storybook/node-logger": "^6.5.6",
|
||||||
"@storybook/preset-create-react-app": "^4.1.1",
|
"@storybook/preset-create-react-app": "^4.1.2",
|
||||||
"@storybook/react": "^6.5.6",
|
"@storybook/react": "^6.5.7",
|
||||||
"@tailwindcss/forms": "^0.5.2",
|
"@tailwindcss/forms": "^0.5.2",
|
||||||
"@testing-library/jest-dom": "^5.16.4",
|
"@testing-library/jest-dom": "^5.16.4",
|
||||||
"@testing-library/react": "^13.3.0",
|
"@testing-library/react": "^13.3.0",
|
||||||
"@testing-library/user-event": "^14.2.0",
|
"@testing-library/user-event": "^14.2.0",
|
||||||
"@types/jest": "^27.5.0",
|
"@types/jest": "^27.5.0",
|
||||||
"@types/lodash": "^4.14.182",
|
"@types/lodash": "^4.14.182",
|
||||||
"@types/node": "^17.0.36",
|
"@types/node": "^17.0.40",
|
||||||
"@types/react": "^18.0.9",
|
"@types/react": "^18.0.9",
|
||||||
"@types/react-dom": "^18.0.5",
|
"@types/react-dom": "^18.0.5",
|
||||||
"@types/styled-components": "^5.1.24",
|
"@types/styled-components": "^5.1.24",
|
||||||
"@types/webpack": "^5.28.0",
|
"@types/webpack": "^5.28.0",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
|
"mini-css-extract-plugin": "^2.6.0",
|
||||||
|
"postcss-loader": "^7.0.0",
|
||||||
"react-scripts": "^5.0.1",
|
"react-scripts": "^5.0.1",
|
||||||
"style-loader": "^3.3.1",
|
"style-loader": "^3.3.1",
|
||||||
"tailwindcss": "^3.0.24",
|
"tailwindcss": "^3.0.24",
|
||||||
"ts-loader": "^9.3.0",
|
"ts-loader": "^9.3.0",
|
||||||
"tsconfig-paths-webpack-plugin": "^3.5.2",
|
"tsconfig-paths-webpack-plugin": "^3.5.2",
|
||||||
"typescript": "^4.7.2",
|
"typescript": "^4.7.3",
|
||||||
"web-vitals": "^2.1.4",
|
"web-vitals": "^2.1.4",
|
||||||
"webpack": "^5.72.1",
|
"webpack": "^5.73.0",
|
||||||
"webpack-cli": "^4.9.2",
|
"webpack-cli": "^4.9.2",
|
||||||
"webpack-dev-server": "^4.9.0"
|
"webpack-dev-server": "^4.9.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "cross-env REACT_APP_FAST_REFRESH=false && start-storybook -p 6006 -s public",
|
"start": "cross-env REACT_APP_FAST_REFRESH=false && start-storybook -p 6006 -s public",
|
||||||
"build": "tsc -b && build-storybook -s public",
|
"build": "tsc -b && tailwindcss -i ./src/tailwind.css -o ./dist/main.css && build-storybook -s public",
|
||||||
"bundle": "webpack",
|
"bundle": "webpack",
|
||||||
"all": "yarn bundle && yarn build",
|
"all": "yarn bundle && yarn build",
|
||||||
"lint": "prettier --check .",
|
"lint": "prettier --check .",
|
||||||
|
|
7
packages/components/postcss.config.js
Normal file
7
packages/components/postcss.config.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
module.exports = {
|
||||||
|
plugins: {
|
||||||
|
tailwindcss: {},
|
||||||
|
autoprefixer: {},
|
||||||
|
cssnano: {},
|
||||||
|
},
|
||||||
|
};
|
|
@ -10,23 +10,32 @@ export const Alert: React.FC<{
|
||||||
backgroundColor: string;
|
backgroundColor: string;
|
||||||
headingColor: string;
|
headingColor: string;
|
||||||
bodyColor: string;
|
bodyColor: string;
|
||||||
icon: React.ReactNode;
|
icon: (props: React.ComponentProps<"svg">) => JSX.Element;
|
||||||
children: React.ReactNode;
|
iconColor: string;
|
||||||
|
children?: React.ReactNode;
|
||||||
}> = ({
|
}> = ({
|
||||||
heading = "Error",
|
heading = "Error",
|
||||||
backgroundColor,
|
backgroundColor,
|
||||||
headingColor,
|
headingColor,
|
||||||
bodyColor,
|
bodyColor,
|
||||||
icon,
|
icon: Icon,
|
||||||
|
iconColor,
|
||||||
children,
|
children,
|
||||||
}) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<div className={`rounded-md p-4 ${backgroundColor}`}>
|
<div className={`rounded-md p-4 ${backgroundColor}`}>
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<div className="flex-shrink-0">{icon}</div>
|
<Icon
|
||||||
|
className={`h-5 w-5 flex-shrink-0 ${iconColor}`}
|
||||||
|
aria-hidden="true"
|
||||||
|
/>
|
||||||
<div className="ml-3">
|
<div className="ml-3">
|
||||||
<h3 className={`text-sm font-medium ${headingColor}`}>{heading}</h3>
|
<header className={`text-sm font-medium ${headingColor}`}>
|
||||||
<div className={`mt-2 text-sm ${bodyColor}`}>{children}</div>
|
{heading}
|
||||||
|
</header>
|
||||||
|
{children && React.Children.count(children) ? (
|
||||||
|
<div className={`mt-2 text-sm ${bodyColor}`}>{children}</div>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -35,49 +44,42 @@ export const Alert: React.FC<{
|
||||||
|
|
||||||
export const ErrorAlert: React.FC<{
|
export const ErrorAlert: React.FC<{
|
||||||
heading: string;
|
heading: string;
|
||||||
children: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
}> = ({ heading = "Error", children }) => (
|
}> = (props) => (
|
||||||
<Alert
|
<Alert
|
||||||
heading={heading}
|
{...props}
|
||||||
children={children}
|
|
||||||
backgroundColor="bg-red-100"
|
backgroundColor="bg-red-100"
|
||||||
headingColor="text-red-800"
|
headingColor="text-red-800"
|
||||||
bodyColor="text-red-700"
|
bodyColor="text-red-700"
|
||||||
icon={<XCircleIcon className="h-5 w-5 text-red-400" aria-hidden="true" />}
|
icon={XCircleIcon}
|
||||||
|
iconColor="text-red-400"
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
export const MessageAlert: React.FC<{
|
export const MessageAlert: React.FC<{
|
||||||
heading: string;
|
heading: string;
|
||||||
children: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
}> = ({ heading = "Error", children }) => (
|
}> = (props) => (
|
||||||
<Alert
|
<Alert
|
||||||
heading={heading}
|
{...props}
|
||||||
children={children}
|
|
||||||
backgroundColor="bg-slate-100"
|
backgroundColor="bg-slate-100"
|
||||||
headingColor="text-slate-700"
|
headingColor="text-slate-700"
|
||||||
bodyColor="text-slate-700"
|
bodyColor="text-slate-700"
|
||||||
icon={
|
icon={InformationCircleIcon}
|
||||||
<InformationCircleIcon
|
iconColor="text-slate-400"
|
||||||
className="h-5 w-5 text-slate-400"
|
|
||||||
aria-hidden="true"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
export const SuccessAlert: React.FC<{
|
export const SuccessAlert: React.FC<{
|
||||||
heading: string;
|
heading: string;
|
||||||
children: React.ReactNode;
|
children?: React.ReactNode;
|
||||||
}> = ({ heading = "Error", children }) => (
|
}> = (props) => (
|
||||||
<Alert
|
<Alert
|
||||||
heading={heading}
|
{...props}
|
||||||
children={children}
|
|
||||||
backgroundColor="bg-green-50"
|
backgroundColor="bg-green-50"
|
||||||
headingColor="text-green-800"
|
headingColor="text-green-800"
|
||||||
bodyColor="text-green-700"
|
bodyColor="text-green-700"
|
||||||
icon={
|
icon={CheckCircleIcon}
|
||||||
<CheckCircleIcon className="h-5 w-5 text-green-400" aria-hidden="true" />
|
iconColor="text-green-400"
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
@ -14,13 +14,13 @@ interface CodeEditorProps {
|
||||||
showGutter?: boolean;
|
showGutter?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export let CodeEditor: FC<CodeEditorProps> = ({
|
export const CodeEditor: FC<CodeEditorProps> = ({
|
||||||
value,
|
value,
|
||||||
onChange,
|
onChange,
|
||||||
oneLine = false,
|
oneLine = false,
|
||||||
showGutter = false,
|
showGutter = false,
|
||||||
height,
|
height,
|
||||||
}: CodeEditorProps) => {
|
}) => {
|
||||||
let lineCount = value.split("\n").length;
|
let lineCount = value.split("\n").length;
|
||||||
let id = _.uniqueId();
|
let id = _.uniqueId();
|
||||||
return (
|
return (
|
||||||
|
@ -48,4 +48,3 @@ export let CodeEditor: FC<CodeEditorProps> = ({
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
export default CodeEditor;
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import _ from "lodash";
|
|
||||||
import {
|
import {
|
||||||
Distribution,
|
Distribution,
|
||||||
result,
|
result,
|
||||||
|
@ -34,71 +33,64 @@ export const DistributionChart: React.FC<DistributionChartProps> = ({
|
||||||
showSummary,
|
showSummary,
|
||||||
width,
|
width,
|
||||||
showControls = false,
|
showControls = false,
|
||||||
}: DistributionChartProps) => {
|
}) => {
|
||||||
let [isLogX, setLogX] = React.useState(false);
|
const [isLogX, setLogX] = React.useState(false);
|
||||||
let [isExpY, setExpY] = React.useState(false);
|
const [isExpY, setExpY] = React.useState(false);
|
||||||
let shape = distribution.pointSet();
|
const shape = distribution.pointSet();
|
||||||
const [sized, _] = useSize((size) => {
|
const [sized] = useSize((size) => {
|
||||||
if (shape.tag === "Ok") {
|
if (shape.tag === "Error") {
|
||||||
let massBelow0 =
|
return (
|
||||||
shape.value.continuous.some((x) => x.x <= 0) ||
|
|
||||||
shape.value.discrete.some((x) => x.x <= 0);
|
|
||||||
let spec = buildVegaSpec(isLogX, isExpY);
|
|
||||||
let widthProp = width ? width : size.width;
|
|
||||||
if (widthProp < 20) {
|
|
||||||
console.warn(
|
|
||||||
`Width of Distribution is set to ${widthProp}, which is too small`
|
|
||||||
);
|
|
||||||
widthProp = 20;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check whether we should disable the checkbox
|
|
||||||
var logCheckbox = (
|
|
||||||
<CheckBox label="Log X scale" value={isLogX} onChange={setLogX} />
|
|
||||||
);
|
|
||||||
if (massBelow0) {
|
|
||||||
logCheckbox = (
|
|
||||||
<CheckBox
|
|
||||||
label="Log X scale"
|
|
||||||
value={isLogX}
|
|
||||||
onChange={setLogX}
|
|
||||||
disabled={true}
|
|
||||||
tooltip={
|
|
||||||
"Your distribution has mass lower than or equal to 0. Log only works on strictly positive values."
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
var result = (
|
|
||||||
<div style={{ width: widthProp + "px" }}>
|
|
||||||
<Vega
|
|
||||||
spec={spec}
|
|
||||||
data={{ con: shape.value.continuous, dis: shape.value.discrete }}
|
|
||||||
width={widthProp - 10}
|
|
||||||
height={height}
|
|
||||||
actions={false}
|
|
||||||
/>
|
|
||||||
<div className="flex justify-center">
|
|
||||||
{showSummary && <SummaryTable distribution={distribution} />}
|
|
||||||
</div>
|
|
||||||
{showControls && (
|
|
||||||
<div>
|
|
||||||
{logCheckbox}
|
|
||||||
<CheckBox label="Exp Y scale" value={isExpY} onChange={setExpY} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
var result = (
|
|
||||||
<ErrorAlert heading="Distribution Error">
|
<ErrorAlert heading="Distribution Error">
|
||||||
{distributionErrorToString(shape.value)}
|
{distributionErrorToString(shape.value)}
|
||||||
</ErrorAlert>
|
</ErrorAlert>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
const massBelow0 =
|
||||||
|
shape.value.continuous.some((x) => x.x <= 0) ||
|
||||||
|
shape.value.discrete.some((x) => x.x <= 0);
|
||||||
|
const spec = buildVegaSpec(isLogX, isExpY);
|
||||||
|
|
||||||
|
let widthProp = width ? width : size.width;
|
||||||
|
if (widthProp < 20) {
|
||||||
|
console.warn(
|
||||||
|
`Width of Distribution is set to ${widthProp}, which is too small`
|
||||||
|
);
|
||||||
|
widthProp = 20;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{ width: widthProp }}>
|
||||||
|
<Vega
|
||||||
|
spec={spec}
|
||||||
|
data={{ con: shape.value.continuous, dis: shape.value.discrete }}
|
||||||
|
width={widthProp - 10}
|
||||||
|
height={height}
|
||||||
|
actions={false}
|
||||||
|
/>
|
||||||
|
<div className="flex justify-center">
|
||||||
|
{showSummary && <SummaryTable distribution={distribution} />}
|
||||||
|
</div>
|
||||||
|
{showControls && (
|
||||||
|
<div>
|
||||||
|
<CheckBox
|
||||||
|
label="Log X scale"
|
||||||
|
value={isLogX}
|
||||||
|
onChange={setLogX}
|
||||||
|
// Check whether we should disable the checkbox
|
||||||
|
{...(massBelow0
|
||||||
|
? {
|
||||||
|
disabled: true,
|
||||||
|
tooltip:
|
||||||
|
"Your distribution has mass lower than or equal to 0. Log only works on strictly positive values.",
|
||||||
|
}
|
||||||
|
: {})}
|
||||||
|
/>
|
||||||
|
<CheckBox label="Exp Y scale" value={isExpY} onChange={setExpY} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
});
|
});
|
||||||
return sized;
|
return sized;
|
||||||
};
|
};
|
||||||
|
@ -121,13 +113,13 @@ interface CheckBoxProps {
|
||||||
tooltip?: string;
|
tooltip?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CheckBox = ({
|
export const CheckBox: React.FC<CheckBoxProps> = ({
|
||||||
label,
|
label,
|
||||||
onChange,
|
onChange,
|
||||||
value,
|
value,
|
||||||
disabled = false,
|
disabled = false,
|
||||||
tooltip,
|
tooltip,
|
||||||
}: CheckBoxProps) => {
|
}) => {
|
||||||
return (
|
return (
|
||||||
<span title={tooltip}>
|
<span title={tooltip}>
|
||||||
<input
|
<input
|
||||||
|
@ -141,22 +133,39 @@ export const CheckBox = ({
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const TableHeadCell: React.FC<{ children: React.ReactNode }> = ({
|
||||||
|
children,
|
||||||
|
}) => (
|
||||||
|
<th className="border border-slate-200 bg-slate-50 py-1 px-2 text-slate-500 font-semibold">
|
||||||
|
{children}
|
||||||
|
</th>
|
||||||
|
);
|
||||||
|
|
||||||
|
const Cell: React.FC<{ children: React.ReactNode }> = ({ children }) => (
|
||||||
|
<td className="border border-slate-200 py-1 px-2 text-slate-900">
|
||||||
|
{children}
|
||||||
|
</td>
|
||||||
|
);
|
||||||
|
|
||||||
type SummaryTableProps = {
|
type SummaryTableProps = {
|
||||||
distribution: Distribution;
|
distribution: Distribution;
|
||||||
};
|
};
|
||||||
|
|
||||||
const SummaryTable: React.FC<SummaryTableProps> = ({
|
const SummaryTable: React.FC<SummaryTableProps> = ({ distribution }) => {
|
||||||
distribution,
|
const mean = distribution.mean();
|
||||||
}: SummaryTableProps) => {
|
const stdev = distribution.stdev();
|
||||||
let mean = distribution.mean();
|
const p5 = distribution.inv(0.05);
|
||||||
let p5 = distribution.inv(0.05);
|
const p10 = distribution.inv(0.1);
|
||||||
let p10 = distribution.inv(0.1);
|
const p25 = distribution.inv(0.25);
|
||||||
let p25 = distribution.inv(0.25);
|
const p50 = distribution.inv(0.5);
|
||||||
let p50 = distribution.inv(0.5);
|
const p75 = distribution.inv(0.75);
|
||||||
let p75 = distribution.inv(0.75);
|
const p90 = distribution.inv(0.9);
|
||||||
let p90 = distribution.inv(0.9);
|
const p95 = distribution.inv(0.95);
|
||||||
let p95 = distribution.inv(0.95);
|
|
||||||
let unwrapResult = (
|
const hasResult = (x: result<number, distributionError>): boolean =>
|
||||||
|
x.tag === "Ok";
|
||||||
|
|
||||||
|
const unwrapResult = (
|
||||||
x: result<number, distributionError>
|
x: result<number, distributionError>
|
||||||
): React.ReactNode => {
|
): React.ReactNode => {
|
||||||
if (x.tag === "Ok") {
|
if (x.tag === "Ok") {
|
||||||
|
@ -170,24 +179,12 @@ const SummaryTable: React.FC<SummaryTableProps> = ({
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let TableHeadCell: React.FC<{ children: React.ReactNode }> = ({
|
|
||||||
children,
|
|
||||||
}) => (
|
|
||||||
<th className="border border-slate-200 bg-slate-50 py-1 px-2 text-slate-500 font-semibold">
|
|
||||||
{children}
|
|
||||||
</th>
|
|
||||||
);
|
|
||||||
let Cell: React.FC<{ children: React.ReactNode }> = ({ children }) => (
|
|
||||||
<td className="border border-slate-200 py-1 px-2 text-slate-900 ">
|
|
||||||
{children}
|
|
||||||
</td>
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<table className="border border-collapse border-slate-400">
|
<table className="border border-collapse border-slate-400">
|
||||||
<thead className="bg-slate-50">
|
<thead className="bg-slate-50">
|
||||||
<tr>
|
<tr>
|
||||||
<TableHeadCell>{"Mean"}</TableHeadCell>
|
<TableHeadCell>{"Mean"}</TableHeadCell>
|
||||||
|
{hasResult(stdev) && <TableHeadCell>{"Stdev"}</TableHeadCell>}
|
||||||
<TableHeadCell>{"5%"}</TableHeadCell>
|
<TableHeadCell>{"5%"}</TableHeadCell>
|
||||||
<TableHeadCell>{"10%"}</TableHeadCell>
|
<TableHeadCell>{"10%"}</TableHeadCell>
|
||||||
<TableHeadCell>{"25%"}</TableHeadCell>
|
<TableHeadCell>{"25%"}</TableHeadCell>
|
||||||
|
@ -200,6 +197,7 @@ const SummaryTable: React.FC<SummaryTableProps> = ({
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<Cell>{unwrapResult(mean)}</Cell>
|
<Cell>{unwrapResult(mean)}</Cell>
|
||||||
|
{hasResult(stdev) && <Cell>{unwrapResult(stdev)}</Cell>}
|
||||||
<Cell>{unwrapResult(p5)}</Cell>
|
<Cell>{unwrapResult(p5)}</Cell>
|
||||||
<Cell>{unwrapResult(p10)}</Cell>
|
<Cell>{unwrapResult(p10)}</Cell>
|
||||||
<Cell>{unwrapResult(p25)}</Cell>
|
<Cell>{unwrapResult(p25)}</Cell>
|
||||||
|
|
|
@ -22,7 +22,7 @@ export const FunctionChart: React.FC<FunctionChartProps> = ({
|
||||||
chartSettings,
|
chartSettings,
|
||||||
environment,
|
environment,
|
||||||
height,
|
height,
|
||||||
}: FunctionChartProps) => {
|
}) => {
|
||||||
if (fn.parameters.length > 1) {
|
if (fn.parameters.length > 1) {
|
||||||
return (
|
return (
|
||||||
<MessageAlert heading="Function Display Not Supported">
|
<MessageAlert heading="Function Display Not Supported">
|
||||||
|
|
|
@ -151,7 +151,7 @@ export const FunctionChart1Dist: React.FC<FunctionChart1DistProps> = ({
|
||||||
chartSettings,
|
chartSettings,
|
||||||
environment,
|
environment,
|
||||||
height,
|
height,
|
||||||
}: FunctionChart1DistProps) => {
|
}) => {
|
||||||
let [mouseOverlay, setMouseOverlay] = React.useState(0);
|
let [mouseOverlay, setMouseOverlay] = React.useState(0);
|
||||||
function handleHover(_name: string, value: unknown) {
|
function handleHover(_name: string, value: unknown) {
|
||||||
setMouseOverlay(value as number);
|
setMouseOverlay(value as number);
|
||||||
|
@ -170,16 +170,14 @@ export const FunctionChart1Dist: React.FC<FunctionChart1DistProps> = ({
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
let showChart =
|
let showChart =
|
||||||
mouseItem.tag === "Ok" && mouseItem.value.tag == "distribution" ? (
|
mouseItem.tag === "Ok" && mouseItem.value.tag === "distribution" ? (
|
||||||
<DistributionChart
|
<DistributionChart
|
||||||
distribution={mouseItem.value.value}
|
distribution={mouseItem.value.value}
|
||||||
width={400}
|
width={400}
|
||||||
height={50}
|
height={50}
|
||||||
showSummary={false}
|
showSummary={false}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : null;
|
||||||
<></>
|
|
||||||
);
|
|
||||||
|
|
||||||
let getPercentilesMemoized = React.useMemo(
|
let getPercentilesMemoized = React.useMemo(
|
||||||
() => getPercentiles({ chartSettings, fn, environment }),
|
() => getPercentiles({ chartSettings, fn, environment }),
|
||||||
|
|
|
@ -14,15 +14,15 @@ interface CodeEditorProps {
|
||||||
showGutter?: boolean;
|
showGutter?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export let JsonEditor: FC<CodeEditorProps> = ({
|
export const JsonEditor: FC<CodeEditorProps> = ({
|
||||||
value,
|
value,
|
||||||
onChange,
|
onChange,
|
||||||
oneLine = false,
|
oneLine = false,
|
||||||
showGutter = false,
|
showGutter = false,
|
||||||
height,
|
height,
|
||||||
}: CodeEditorProps) => {
|
}) => {
|
||||||
let lineCount = value.split("\n").length;
|
const lineCount = value.split("\n").length;
|
||||||
let id = _.uniqueId();
|
const id = _.uniqueId();
|
||||||
return (
|
return (
|
||||||
<AceEditor
|
<AceEditor
|
||||||
value={value}
|
value={value}
|
||||||
|
@ -47,5 +47,3 @@ export let JsonEditor: FC<CodeEditorProps> = ({
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default JsonEditor;
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import _ from "lodash";
|
|
||||||
|
|
||||||
const orderOfMagnitudeNum = (n: number) => {
|
const orderOfMagnitudeNum = (n: number) => {
|
||||||
return Math.pow(10, n);
|
return Math.pow(10, n);
|
||||||
|
@ -74,25 +73,23 @@ export interface NumberShowerProps {
|
||||||
precision?: number;
|
precision?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export let NumberShower: React.FC<NumberShowerProps> = ({
|
export const NumberShower: React.FC<NumberShowerProps> = ({
|
||||||
number,
|
number,
|
||||||
precision = 2,
|
precision = 2,
|
||||||
}: NumberShowerProps) => {
|
}) => {
|
||||||
let numberWithPresentation = numberShow(number, precision);
|
const numberWithPresentation = numberShow(number, precision);
|
||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
{numberWithPresentation.value}
|
{numberWithPresentation.value}
|
||||||
{numberWithPresentation.symbol}
|
{numberWithPresentation.symbol}
|
||||||
{numberWithPresentation.power ? (
|
{numberWithPresentation.power ? (
|
||||||
<span>
|
<span>
|
||||||
{"\u00b710"}
|
{"\u00b7" /* dot symbol */}10
|
||||||
<span style={{ fontSize: "0.6em", verticalAlign: "super" }}>
|
<span style={{ fontSize: "0.6em", verticalAlign: "super" }}>
|
||||||
{numberWithPresentation.power}
|
{numberWithPresentation.power}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : null}
|
||||||
<></>
|
|
||||||
)}
|
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import _ from "lodash";
|
|
||||||
import {
|
import {
|
||||||
run,
|
run,
|
||||||
errorValueToString,
|
errorValueToString,
|
||||||
|
@ -28,6 +27,7 @@ function getRange<a>(x: declaration<a>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getChartSettings<a>(x: declaration<a>): FunctionChartSettings {
|
function getChartSettings<a>(x: declaration<a>): FunctionChartSettings {
|
||||||
let range = getRange(x);
|
let range = getRange(x);
|
||||||
let min = range.floats ? range.floats.min : 0;
|
let min = range.floats ? range.floats.min : 0;
|
||||||
|
@ -49,12 +49,12 @@ export const VariableBox: React.FC<VariableBoxProps> = ({
|
||||||
heading = "Error",
|
heading = "Error",
|
||||||
children,
|
children,
|
||||||
showTypes = false,
|
showTypes = false,
|
||||||
}: VariableBoxProps) => {
|
}) => {
|
||||||
if (showTypes) {
|
if (showTypes) {
|
||||||
return (
|
return (
|
||||||
<div className="bg-white border border-grey-200 m-2">
|
<div className="bg-white border border-grey-200 m-2">
|
||||||
<div className="border-b border-grey-200 p-3">
|
<div className="border-b border-grey-200 p-3">
|
||||||
<h3 className="font-mono">{heading}</h3>
|
<header className="font-mono">{heading}</header>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-3">{children}</div>
|
<div className="p-3">{children}</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -90,7 +90,7 @@ const SquiggleItem: React.FC<SquiggleItemProps> = ({
|
||||||
showControls = false,
|
showControls = false,
|
||||||
chartSettings,
|
chartSettings,
|
||||||
environment,
|
environment,
|
||||||
}: SquiggleItemProps) => {
|
}) => {
|
||||||
switch (expression.tag) {
|
switch (expression.tag) {
|
||||||
case "number":
|
case "number":
|
||||||
return (
|
return (
|
||||||
|
@ -108,12 +108,8 @@ const SquiggleItem: React.FC<SquiggleItemProps> = ({
|
||||||
showTypes={showTypes}
|
showTypes={showTypes}
|
||||||
>
|
>
|
||||||
{distType === "Symbolic" && showTypes ? (
|
{distType === "Symbolic" && showTypes ? (
|
||||||
<>
|
<div>{expression.value.toString()}</div>
|
||||||
<div>{expression.value.toString()}</div>
|
) : null}
|
||||||
</>
|
|
||||||
) : (
|
|
||||||
<></>
|
|
||||||
)}
|
|
||||||
<DistributionChart
|
<DistributionChart
|
||||||
distribution={expression.value}
|
distribution={expression.value}
|
||||||
height={height}
|
height={height}
|
||||||
|
@ -157,11 +153,11 @@ const SquiggleItem: React.FC<SquiggleItemProps> = ({
|
||||||
return (
|
return (
|
||||||
<VariableBox heading="Array" showTypes={showTypes}>
|
<VariableBox heading="Array" showTypes={showTypes}>
|
||||||
{expression.value.map((r, i) => (
|
{expression.value.map((r, i) => (
|
||||||
<div key={i} className="flex flex-row pt-1">
|
<div key={i} className="flex pt-1">
|
||||||
<div className="flex-none bg-slate-100 rounded-sm px-1">
|
<div className="flex-none bg-slate-100 rounded-sm px-1">
|
||||||
<h3 className="text-slate-400 font-mono">{i}</h3>
|
<header className="text-slate-400 font-mono">{i}</header>
|
||||||
</div>
|
</div>
|
||||||
<div className="px-2 mb-2 grow ">
|
<div className="px-2 mb-2 grow">
|
||||||
<SquiggleItem
|
<SquiggleItem
|
||||||
key={i}
|
key={i}
|
||||||
expression={r}
|
expression={r}
|
||||||
|
@ -181,25 +177,27 @@ const SquiggleItem: React.FC<SquiggleItemProps> = ({
|
||||||
case "record":
|
case "record":
|
||||||
return (
|
return (
|
||||||
<VariableBox heading="Record" showTypes={showTypes}>
|
<VariableBox heading="Record" showTypes={showTypes}>
|
||||||
{Object.entries(expression.value).map(([key, r]) => (
|
<div className="space-y-3">
|
||||||
<div key={key} className="flex flex-row pt-1">
|
{Object.entries(expression.value).map(([key, r]) => (
|
||||||
<div className="flex-none pr-2">
|
<div key={key} className="flex space-x-2">
|
||||||
<h3 className="text-slate-500 font-mono">{key}:</h3>
|
<div className="flex-none">
|
||||||
|
<header className="text-slate-500 font-mono">{key}:</header>
|
||||||
|
</div>
|
||||||
|
<div className="px-2 grow bg-gray-50 border border-gray-100 rounded-sm">
|
||||||
|
<SquiggleItem
|
||||||
|
expression={r}
|
||||||
|
width={width !== undefined ? width - 20 : width}
|
||||||
|
height={height / 3}
|
||||||
|
showTypes={showTypes}
|
||||||
|
showSummary={showSummary}
|
||||||
|
showControls={showControls}
|
||||||
|
chartSettings={chartSettings}
|
||||||
|
environment={environment}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="pl-2 pr-2 mb-2 grow bg-gray-50 border border-gray-100 rounded-sm">
|
))}
|
||||||
<SquiggleItem
|
</div>
|
||||||
expression={r}
|
|
||||||
width={width !== undefined ? width - 20 : width}
|
|
||||||
height={height / 3}
|
|
||||||
showTypes={showTypes}
|
|
||||||
showSummary={showSummary}
|
|
||||||
showControls={showControls}
|
|
||||||
chartSettings={chartSettings}
|
|
||||||
environment={environment}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</VariableBox>
|
</VariableBox>
|
||||||
);
|
);
|
||||||
case "arraystring":
|
case "arraystring":
|
||||||
|
@ -285,7 +283,7 @@ export interface SquiggleChartProps {
|
||||||
showControls?: boolean;
|
showControls?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
let defaultChartSettings = { start: 0, stop: 10, count: 20 };
|
const defaultChartSettings = { start: 0, stop: 10, count: 20 };
|
||||||
|
|
||||||
export const SquiggleChart: React.FC<SquiggleChartProps> = ({
|
export const SquiggleChart: React.FC<SquiggleChartProps> = ({
|
||||||
squiggleString = "",
|
squiggleString = "",
|
||||||
|
@ -299,31 +297,29 @@ export const SquiggleChart: React.FC<SquiggleChartProps> = ({
|
||||||
showTypes = false,
|
showTypes = false,
|
||||||
showControls = false,
|
showControls = false,
|
||||||
chartSettings = defaultChartSettings,
|
chartSettings = defaultChartSettings,
|
||||||
}: SquiggleChartProps) => {
|
}) => {
|
||||||
let expressionResult = run(squiggleString, bindings, environment, jsImports);
|
let expressionResult = run(squiggleString, bindings, environment, jsImports);
|
||||||
let e = environment ? environment : defaultEnvironment;
|
if (expressionResult.tag !== "Ok") {
|
||||||
let internal: JSX.Element;
|
return (
|
||||||
if (expressionResult.tag === "Ok") {
|
|
||||||
let expression = expressionResult.value;
|
|
||||||
onChange(expression);
|
|
||||||
internal = (
|
|
||||||
<SquiggleItem
|
|
||||||
expression={expression}
|
|
||||||
width={width}
|
|
||||||
height={height}
|
|
||||||
showSummary={showSummary}
|
|
||||||
showTypes={showTypes}
|
|
||||||
showControls={showControls}
|
|
||||||
chartSettings={chartSettings}
|
|
||||||
environment={e}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
internal = (
|
|
||||||
<ErrorAlert heading={"Parse Error"}>
|
<ErrorAlert heading={"Parse Error"}>
|
||||||
{errorValueToString(expressionResult.value)}
|
{errorValueToString(expressionResult.value)}
|
||||||
</ErrorAlert>
|
</ErrorAlert>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return internal;
|
|
||||||
|
let e = environment ?? defaultEnvironment;
|
||||||
|
let expression = expressionResult.value;
|
||||||
|
onChange(expression);
|
||||||
|
return (
|
||||||
|
<SquiggleItem
|
||||||
|
expression={expression}
|
||||||
|
width={width}
|
||||||
|
height={height}
|
||||||
|
showSummary={showSummary}
|
||||||
|
showTypes={showTypes}
|
||||||
|
showControls={showControls}
|
||||||
|
chartSettings={chartSettings}
|
||||||
|
environment={e}
|
||||||
|
/>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -57,8 +57,8 @@ export let SquiggleEditor: React.FC<SquiggleEditorProps> = ({
|
||||||
showControls = false,
|
showControls = false,
|
||||||
showSummary = false,
|
showSummary = false,
|
||||||
}: SquiggleEditorProps) => {
|
}: SquiggleEditorProps) => {
|
||||||
let [expression, setExpression] = React.useState(initialSquiggleString);
|
const [expression, setExpression] = React.useState(initialSquiggleString);
|
||||||
let chartSettings = {
|
const chartSettings = {
|
||||||
start: diagramStart,
|
start: diagramStart,
|
||||||
stop: diagramStop,
|
stop: diagramStop,
|
||||||
count: diagramCount,
|
count: diagramCount,
|
||||||
|
@ -150,17 +150,17 @@ export let SquigglePartial: React.FC<SquigglePartialProps> = ({
|
||||||
environment,
|
environment,
|
||||||
jsImports = defaultImports,
|
jsImports = defaultImports,
|
||||||
}: SquigglePartialProps) => {
|
}: SquigglePartialProps) => {
|
||||||
let [expression, setExpression] = React.useState(initialSquiggleString);
|
const [expression, setExpression] = React.useState(initialSquiggleString);
|
||||||
let [error, setError] = React.useState<string | null>(null);
|
const [error, setError] = React.useState<string | null>(null);
|
||||||
|
|
||||||
let runSquiggleAndUpdateBindings = () => {
|
const runSquiggleAndUpdateBindings = () => {
|
||||||
let squiggleResult = runPartial(
|
const squiggleResult = runPartial(
|
||||||
expression,
|
expression,
|
||||||
bindings,
|
bindings,
|
||||||
environment,
|
environment,
|
||||||
jsImports
|
jsImports
|
||||||
);
|
);
|
||||||
if (squiggleResult.tag == "Ok") {
|
if (squiggleResult.tag === "Ok") {
|
||||||
if (onChange) onChange(squiggleResult.value);
|
if (onChange) onChange(squiggleResult.value);
|
||||||
setError(null);
|
setError(null);
|
||||||
} else {
|
} else {
|
||||||
|
@ -181,11 +181,7 @@ export let SquigglePartial: React.FC<SquigglePartialProps> = ({
|
||||||
height={20}
|
height={20}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{error !== null ? (
|
{error !== null ? <ErrorAlert heading="Error">{error}</ErrorAlert> : null}
|
||||||
<ErrorAlert heading="Error">{error}</ErrorAlert>
|
|
||||||
) : (
|
|
||||||
<></>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,19 +1,21 @@
|
||||||
import _ from "lodash";
|
import React, { FC, Fragment, useState } from "react";
|
||||||
import React, { FC, ReactElement, useState } from "react";
|
|
||||||
import ReactDOM from "react-dom";
|
import ReactDOM from "react-dom";
|
||||||
import { SquiggleChart } from "./SquiggleChart";
|
import { Path, useForm, UseFormRegister, useWatch } from "react-hook-form";
|
||||||
import CodeEditor from "./CodeEditor";
|
|
||||||
import JsonEditor from "./JsonEditor";
|
|
||||||
import { useForm, useWatch } from "react-hook-form";
|
|
||||||
import * as yup from "yup";
|
import * as yup from "yup";
|
||||||
import { yupResolver } from "@hookform/resolvers/yup";
|
import { yupResolver } from "@hookform/resolvers/yup";
|
||||||
import { defaultBindings, environment } from "@quri/squiggle-lang";
|
|
||||||
import { Tab } from "@headlessui/react";
|
import { Tab } from "@headlessui/react";
|
||||||
import { CodeIcon } from "@heroicons/react/solid";
|
import {
|
||||||
import { CogIcon } from "@heroicons/react/solid";
|
ChartSquareBarIcon,
|
||||||
import { ChartSquareBarIcon } from "@heroicons/react/solid";
|
CodeIcon,
|
||||||
import { CurrencyDollarIcon } from "@heroicons/react/solid";
|
CogIcon,
|
||||||
import { Fragment } from "react";
|
CurrencyDollarIcon,
|
||||||
|
} from "@heroicons/react/solid";
|
||||||
|
|
||||||
|
import { defaultBindings, environment } from "@quri/squiggle-lang";
|
||||||
|
|
||||||
|
import { SquiggleChart } from "./SquiggleChart";
|
||||||
|
import { CodeEditor } from "./CodeEditor";
|
||||||
|
import { JsonEditor } from "./JsonEditor";
|
||||||
import { ErrorAlert, SuccessAlert } from "./Alert";
|
import { ErrorAlert, SuccessAlert } from "./Alert";
|
||||||
|
|
||||||
interface PlaygroundProps {
|
interface PlaygroundProps {
|
||||||
|
@ -85,49 +87,20 @@ const schema = yup
|
||||||
})
|
})
|
||||||
.required();
|
.required();
|
||||||
|
|
||||||
type InputProps = {
|
|
||||||
label: string;
|
|
||||||
children: ReactElement;
|
|
||||||
};
|
|
||||||
|
|
||||||
const InputItem: React.FC<InputProps> = ({ label, children }) => (
|
|
||||||
<div className="col-span-4">
|
|
||||||
<label className="block text-sm font-medium text-gray-600">{label}</label>
|
|
||||||
<div className="mt-1">{children}</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
|
||||||
let numberStyle =
|
|
||||||
"max-w-lg block w-full shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:max-w-xs sm:text-sm border-gray-300 rounded-md";
|
|
||||||
|
|
||||||
function classNames(...classes: string[]) {
|
function classNames(...classes: string[]) {
|
||||||
return classes.filter(Boolean).join(" ");
|
return classes.filter(Boolean).join(" ");
|
||||||
}
|
}
|
||||||
|
|
||||||
type StyledTabProps = {
|
type StyledTabProps = {
|
||||||
name: string;
|
name: string;
|
||||||
iconName: string;
|
icon: (props: React.ComponentProps<"svg">) => JSX.Element;
|
||||||
};
|
};
|
||||||
|
|
||||||
const StyledTab: React.FC<StyledTabProps> = ({ name, iconName }) => {
|
const StyledTab: React.FC<StyledTabProps> = ({ name, icon: Icon }) => {
|
||||||
let iconStyle = (isSelected: boolean) =>
|
|
||||||
classNames(
|
|
||||||
"-ml-0.5 mr-2 h-4 w-4 ",
|
|
||||||
isSelected ? "text-slate-500" : "text-gray-400 group-hover:text-gray-900"
|
|
||||||
);
|
|
||||||
|
|
||||||
let icon = (selected: boolean) =>
|
|
||||||
({
|
|
||||||
code: <CodeIcon className={iconStyle(selected)} />,
|
|
||||||
cog: <CogIcon className={iconStyle(selected)} />,
|
|
||||||
squareBar: <ChartSquareBarIcon className={iconStyle(selected)} />,
|
|
||||||
dollar: <CurrencyDollarIcon className={iconStyle(selected)} />,
|
|
||||||
}[iconName]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tab key={name} as={Fragment}>
|
<Tab key={name} as={Fragment}>
|
||||||
{({ selected }) => (
|
{({ selected }) => (
|
||||||
<button className="flex rounded-md focus:outline-none focus-visible:ring-offset-gray-100 ">
|
<button className="group flex rounded-md focus:outline-none focus-visible:ring-offset-gray-100">
|
||||||
<span
|
<span
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"p-1 pl-2.5 pr-3.5 rounded-md flex items-center text-sm font-medium",
|
"p-1 pl-2.5 pr-3.5 rounded-md flex items-center text-sm font-medium",
|
||||||
|
@ -136,7 +109,14 @@ const StyledTab: React.FC<StyledTabProps> = ({ name, iconName }) => {
|
||||||
: ""
|
: ""
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{icon(selected)}
|
<Icon
|
||||||
|
className={classNames(
|
||||||
|
"-ml-0.5 mr-2 h-4 w-4",
|
||||||
|
selected
|
||||||
|
? "text-slate-500"
|
||||||
|
: "text-gray-400 group-hover:text-gray-900"
|
||||||
|
)}
|
||||||
|
/>
|
||||||
<span
|
<span
|
||||||
className={
|
className={
|
||||||
selected
|
selected
|
||||||
|
@ -153,17 +133,77 @@ const StyledTab: React.FC<StyledTabProps> = ({ name, iconName }) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
let SquigglePlayground: FC<PlaygroundProps> = ({
|
const HeadedSection: FC<{ title: string; children: React.ReactNode }> = ({
|
||||||
|
title,
|
||||||
|
children,
|
||||||
|
}) => (
|
||||||
|
<div>
|
||||||
|
<header className="text-lg leading-6 font-medium text-gray-900">
|
||||||
|
{title}
|
||||||
|
</header>
|
||||||
|
<div className="mt-4">{children}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const Text: FC<{ children: React.ReactNode }> = ({ children }) => (
|
||||||
|
<p className="text-sm text-gray-500">{children}</p>
|
||||||
|
);
|
||||||
|
|
||||||
|
function InputItem<T>({
|
||||||
|
name,
|
||||||
|
label,
|
||||||
|
type,
|
||||||
|
register,
|
||||||
|
}: {
|
||||||
|
name: Path<T>;
|
||||||
|
label: string;
|
||||||
|
type: "number";
|
||||||
|
register: UseFormRegister<T>;
|
||||||
|
}) {
|
||||||
|
const numberStyle =
|
||||||
|
"max-w-lg block w-full shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:max-w-xs sm:text-sm border-gray-300 rounded-md";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<label className="block">
|
||||||
|
<div className="text-sm font-medium text-gray-600 mb-1">{label}</div>
|
||||||
|
<input type={type} {...register(name)} className={numberStyle} />
|
||||||
|
</label>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function Checkbox<T>({
|
||||||
|
name,
|
||||||
|
label,
|
||||||
|
register,
|
||||||
|
}: {
|
||||||
|
name: Path<T>;
|
||||||
|
label: string;
|
||||||
|
register: UseFormRegister<T>;
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<label className="flex items-center">
|
||||||
|
<input
|
||||||
|
type="checkbox"
|
||||||
|
{...register(name)}
|
||||||
|
className="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded"
|
||||||
|
/>
|
||||||
|
{/* Clicking on the div makes the checkbox lose focus while mouse button is pressed, leading to annoying blinking; I couldn't figure out how to fix this. */}
|
||||||
|
<div className="ml-3 text-sm font-medium text-gray-700">{label}</div>
|
||||||
|
</label>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const SquigglePlayground: FC<PlaygroundProps> = ({
|
||||||
initialSquiggleString = "",
|
initialSquiggleString = "",
|
||||||
height = 500,
|
height = 500,
|
||||||
showTypes = false,
|
showTypes = false,
|
||||||
showControls = false,
|
showControls = false,
|
||||||
showSummary = false,
|
showSummary = false,
|
||||||
}: PlaygroundProps) => {
|
}) => {
|
||||||
let [squiggleString, setSquiggleString] = useState(initialSquiggleString);
|
const [squiggleString, setSquiggleString] = useState(initialSquiggleString);
|
||||||
let [importString, setImportString] = useState("{}");
|
const [importString, setImportString] = useState("{}");
|
||||||
let [imports, setImports] = useState({});
|
const [imports, setImports] = useState({});
|
||||||
let [importsAreValid, setImportsAreValid] = useState(true);
|
const [importsAreValid, setImportsAreValid] = useState(true);
|
||||||
const { register, control } = useForm({
|
const { register, control } = useForm({
|
||||||
resolver: yupResolver(schema),
|
resolver: yupResolver(schema),
|
||||||
defaultValues: {
|
defaultValues: {
|
||||||
|
@ -183,16 +223,16 @@ let SquigglePlayground: FC<PlaygroundProps> = ({
|
||||||
const vars = useWatch({
|
const vars = useWatch({
|
||||||
control,
|
control,
|
||||||
});
|
});
|
||||||
let chartSettings = {
|
const chartSettings = {
|
||||||
start: Number(vars.diagramStart),
|
start: Number(vars.diagramStart),
|
||||||
stop: Number(vars.diagramStop),
|
stop: Number(vars.diagramStop),
|
||||||
count: Number(vars.diagramCount),
|
count: Number(vars.diagramCount),
|
||||||
};
|
};
|
||||||
let env: environment = {
|
const env: environment = {
|
||||||
sampleCount: Number(vars.sampleCount),
|
sampleCount: Number(vars.sampleCount),
|
||||||
xyPointLength: Number(vars.xyPointLength),
|
xyPointLength: Number(vars.xyPointLength),
|
||||||
};
|
};
|
||||||
let getChangeJson = (r: string) => {
|
const getChangeJson = (r: string) => {
|
||||||
setImportString(r);
|
setImportString(r);
|
||||||
try {
|
try {
|
||||||
setImports(JSON.parse(r));
|
setImports(JSON.parse(r));
|
||||||
|
@ -202,217 +242,184 @@ let SquigglePlayground: FC<PlaygroundProps> = ({
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let samplingSettings = (
|
const samplingSettings = (
|
||||||
<div className="space-y-6 p-3 max-w-xl">
|
<div className="space-y-6 p-3 max-w-xl">
|
||||||
<InputItem label="Sample Count">
|
<div>
|
||||||
<>
|
<InputItem
|
||||||
<input
|
name="sampleCount"
|
||||||
type="number"
|
type="number"
|
||||||
{...register("sampleCount")}
|
label="Sample Count"
|
||||||
className={numberStyle}
|
register={register}
|
||||||
/>
|
/>
|
||||||
<p className="mt-2 text-sm text-gray-500">
|
<div className="mt-2">
|
||||||
|
<Text>
|
||||||
How many samples to use for Monte Carlo simulations. This can
|
How many samples to use for Monte Carlo simulations. This can
|
||||||
occasionally be overridden by specific Squiggle programs.
|
occasionally be overridden by specific Squiggle programs.
|
||||||
</p>
|
</Text>
|
||||||
</>
|
</div>
|
||||||
</InputItem>
|
</div>
|
||||||
<InputItem label="Coordinate Count (For PointSet Shapes)">
|
<div>
|
||||||
<>
|
<InputItem
|
||||||
<input
|
name="xyPointLength"
|
||||||
type="number"
|
type="number"
|
||||||
{...register("xyPointLength")}
|
register={register}
|
||||||
className={numberStyle}
|
label="Coordinate Count (For PointSet Shapes)"
|
||||||
/>
|
/>
|
||||||
<p className="mt-2 text-sm text-gray-500">
|
<div className="mt-2">
|
||||||
|
<Text>
|
||||||
When distributions are converted into PointSet shapes, we need to
|
When distributions are converted into PointSet shapes, we need to
|
||||||
know how many coordinates to use.
|
know how many coordinates to use.
|
||||||
</p>
|
</Text>
|
||||||
</>
|
</div>
|
||||||
</InputItem>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
let viewSettings = (
|
const viewSettings = (
|
||||||
<div className="space-y-6 p-3 divide-y divide-gray-200 max-w-xl">
|
<div className="space-y-6 p-3 divide-y divide-gray-200 max-w-xl">
|
||||||
<div className="space-y-2">
|
<HeadedSection title="General Display Settings">
|
||||||
<h3 className="text-lg leading-6 font-medium text-gray-900 pb-2">
|
<div className="space-y-4">
|
||||||
General Display Settings
|
<InputItem
|
||||||
</h3>
|
name="chartHeight"
|
||||||
<InputItem label="Chart Height (in pixels)">
|
|
||||||
<input
|
|
||||||
type="number"
|
type="number"
|
||||||
{...register("chartHeight")}
|
register={register}
|
||||||
className={numberStyle}
|
label="Chart Height (in pixels)"
|
||||||
/>
|
/>
|
||||||
</InputItem>
|
<Checkbox
|
||||||
<div className="relative flex items-start pt-3">
|
name="showTypes"
|
||||||
<div className="flex items-center h-5">
|
register={register}
|
||||||
<input
|
label="Show information about displayed types"
|
||||||
type="checkbox"
|
/>
|
||||||
{...register("showTypes")}
|
</div>
|
||||||
className="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded"
|
</HeadedSection>
|
||||||
|
|
||||||
|
<div className="pt-8">
|
||||||
|
<HeadedSection title="Distribution Display Settings">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Checkbox
|
||||||
|
register={register}
|
||||||
|
name="showControls"
|
||||||
|
label="Show toggles to adjust scale of x and y axes"
|
||||||
|
/>
|
||||||
|
<Checkbox
|
||||||
|
register={register}
|
||||||
|
name="showSummary"
|
||||||
|
label="Show summary statistics"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-3 text-sm">
|
</HeadedSection>
|
||||||
<label className="font-medium text-gray-700">
|
|
||||||
Show information about displayed types.
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2 pt-8">
|
<div className="pt-8">
|
||||||
<h3 className="text-lg leading-6 font-medium text-gray-900 pb-2">
|
<HeadedSection title="Function Display Settings">
|
||||||
Distribution Display Settings
|
<div className="space-y-6">
|
||||||
</h3>
|
<Text>
|
||||||
|
When displaying functions of single variables that return numbers
|
||||||
<div className="relative flex items-start">
|
or distributions, we need to use defaults for the x-axis. We need
|
||||||
<div className="flex items-center h-5">
|
to select a minimum and maximum value of x to sample, and a number
|
||||||
<input
|
n of the number of points to sample.
|
||||||
type="checkbox"
|
</Text>
|
||||||
{...register("showControls")}
|
<div className="space-y-4">
|
||||||
className="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded"
|
<InputItem
|
||||||
/>
|
type="number"
|
||||||
|
name="diagramStart"
|
||||||
|
register={register}
|
||||||
|
label="Min X Value"
|
||||||
|
/>
|
||||||
|
<InputItem
|
||||||
|
type="number"
|
||||||
|
name="diagramStop"
|
||||||
|
register={register}
|
||||||
|
label="Max X Value"
|
||||||
|
/>
|
||||||
|
<InputItem
|
||||||
|
type="number"
|
||||||
|
name="diagramCount"
|
||||||
|
register={register}
|
||||||
|
label="Points between X min and X max to sample"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-3 text-sm">
|
</HeadedSection>
|
||||||
<label className="font-medium text-gray-700">
|
|
||||||
Show toggles to adjust scale of x and y axes
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="relative flex items-start">
|
|
||||||
<div className="flex items-center h-5">
|
|
||||||
<input
|
|
||||||
type="checkbox"
|
|
||||||
{...register("showSummary")}
|
|
||||||
className="focus:ring-indigo-500 h-4 w-4 text-indigo-600 border-gray-300 rounded"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className="ml-3 text-sm">
|
|
||||||
<label className="font-medium text-gray-700">
|
|
||||||
Show summary statistics
|
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="space-y-2 pt-8">
|
|
||||||
<h3 className="text-lg leading-6 font-medium text-gray-900 pb-2">
|
|
||||||
Function Display Settings
|
|
||||||
</h3>
|
|
||||||
|
|
||||||
<p className="mt-2 text-sm text-gray-500">
|
|
||||||
When displaying functions of single variables that return numbers or
|
|
||||||
distributions, we need to use defaults for the x-axis. We need to
|
|
||||||
select a minimum and maximum value of x to sample, and a number n of
|
|
||||||
the number of points to sample.
|
|
||||||
</p>
|
|
||||||
<div className="pt-4 grid grid-cols-1 gap-y-4 gap-x-4">
|
|
||||||
<InputItem label="Min X Value">
|
|
||||||
<input
|
|
||||||
type="number"
|
|
||||||
{...register("diagramStart")}
|
|
||||||
className={numberStyle}
|
|
||||||
/>
|
|
||||||
</InputItem>
|
|
||||||
<InputItem label="Max X Value">
|
|
||||||
<input
|
|
||||||
type="number"
|
|
||||||
{...register("diagramStop")}
|
|
||||||
className={numberStyle}
|
|
||||||
/>
|
|
||||||
</InputItem>
|
|
||||||
<InputItem label="Points between X min and X max to sample">
|
|
||||||
<input
|
|
||||||
type="number"
|
|
||||||
{...register("diagramCount")}
|
|
||||||
className={numberStyle}
|
|
||||||
/>
|
|
||||||
</InputItem>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
let inputVariableSettings = (
|
const inputVariableSettings = (
|
||||||
<div className="space-y-6 p-3 max-w-3xl">
|
<div className="p-3 max-w-3xl">
|
||||||
<h3 className="text-lg leading-6 font-medium text-gray-900">
|
<HeadedSection title="Import Variables from JSON">
|
||||||
Import Variables from JSON
|
<div className="space-y-6">
|
||||||
</h3>
|
<Text>
|
||||||
<p className="mt-2 text-sm text-gray-500">
|
You can import variables from JSON into your Squiggle code.
|
||||||
You can import variables from JSON into your Squiggle code. Variables
|
Variables are accessed with dollar signs. For example, "timeNow"
|
||||||
are accessed with dollar signs. For example, "timeNow" would be accessed
|
would be accessed as "$timeNow".
|
||||||
as "$timeNow".
|
</Text>
|
||||||
</p>
|
<div className="border border-slate-200 mt-6 mb-2">
|
||||||
<div className="border border-slate-200 mt-6 mb-2">
|
<JsonEditor
|
||||||
<JsonEditor
|
value={importString}
|
||||||
value={importString}
|
onChange={getChangeJson}
|
||||||
onChange={getChangeJson}
|
oneLine={false}
|
||||||
oneLine={false}
|
showGutter={true}
|
||||||
showGutter={true}
|
height={150}
|
||||||
height={150}
|
/>
|
||||||
/>
|
</div>
|
||||||
</div>
|
<div className="p-1 pt-2">
|
||||||
<div className="p-1 pt-2">
|
{importsAreValid ? (
|
||||||
{importsAreValid ? (
|
<SuccessAlert heading="Valid JSON" />
|
||||||
<SuccessAlert heading="Valid Json">
|
) : (
|
||||||
<></>
|
<ErrorAlert heading="Invalid JSON">
|
||||||
</SuccessAlert>
|
You must use valid JSON in this editor.
|
||||||
) : (
|
</ErrorAlert>
|
||||||
<ErrorAlert heading="Invalid JSON">
|
)}
|
||||||
You must use valid json in this editor.
|
</div>
|
||||||
</ErrorAlert>
|
</div>
|
||||||
)}
|
</HeadedSection>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tab.Group>
|
<Tab.Group>
|
||||||
<div className=" flex-col flex">
|
<div className="pb-4">
|
||||||
<div className="pb-4">
|
<Tab.List className="flex w-fit p-0.5 rounded-md bg-slate-100 hover:bg-slate-200">
|
||||||
<Tab.List className="p-0.5 rounded-md bg-slate-100 hover:bg-slate-200 inline-flex">
|
<StyledTab name="Code" icon={CodeIcon} />
|
||||||
<StyledTab name="Code" iconName="code" />
|
<StyledTab name="Sampling Settings" icon={CogIcon} />
|
||||||
<StyledTab name="Sampling Settings" iconName="cog" />
|
<StyledTab name="View Settings" icon={ChartSquareBarIcon} />
|
||||||
<StyledTab name="View Settings" iconName="squareBar" />
|
<StyledTab name="Input Variables" icon={CurrencyDollarIcon} />
|
||||||
<StyledTab name="Input Variables" iconName="dollar" />
|
</Tab.List>
|
||||||
</Tab.List>
|
</div>
|
||||||
|
<div className="flex" style={{ height }}>
|
||||||
|
<div className="w-1/2">
|
||||||
|
<Tab.Panels>
|
||||||
|
<Tab.Panel>
|
||||||
|
<div className="border border-slate-200">
|
||||||
|
<CodeEditor
|
||||||
|
value={squiggleString}
|
||||||
|
onChange={setSquiggleString}
|
||||||
|
oneLine={false}
|
||||||
|
showGutter={true}
|
||||||
|
height={height - 1}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Tab.Panel>
|
||||||
|
<Tab.Panel>{samplingSettings}</Tab.Panel>
|
||||||
|
<Tab.Panel>{viewSettings}</Tab.Panel>
|
||||||
|
<Tab.Panel>{inputVariableSettings}</Tab.Panel>
|
||||||
|
</Tab.Panels>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex" style={{ height: height + "px" }}>
|
|
||||||
<div className="w-1/2">
|
|
||||||
<Tab.Panels>
|
|
||||||
<Tab.Panel>
|
|
||||||
<div className="border border-slate-200">
|
|
||||||
<CodeEditor
|
|
||||||
value={squiggleString}
|
|
||||||
onChange={setSquiggleString}
|
|
||||||
oneLine={false}
|
|
||||||
showGutter={true}
|
|
||||||
height={height - 1}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</Tab.Panel>
|
|
||||||
<Tab.Panel>{samplingSettings}</Tab.Panel>
|
|
||||||
<Tab.Panel>{viewSettings}</Tab.Panel>
|
|
||||||
<Tab.Panel>{inputVariableSettings}</Tab.Panel>
|
|
||||||
</Tab.Panels>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="w-1/2 p-2 pl-4">
|
<div className="w-1/2 p-2 pl-4">
|
||||||
<div style={{ maxHeight: height + "px" }}>
|
<div style={{ maxHeight: height }}>
|
||||||
<SquiggleChart
|
<SquiggleChart
|
||||||
squiggleString={squiggleString}
|
squiggleString={squiggleString}
|
||||||
environment={env}
|
environment={env}
|
||||||
chartSettings={chartSettings}
|
chartSettings={chartSettings}
|
||||||
height={vars.chartHeight}
|
height={vars.chartHeight}
|
||||||
showTypes={vars.showTypes}
|
showTypes={vars.showTypes}
|
||||||
showControls={vars.showControls}
|
showControls={vars.showControls}
|
||||||
bindings={defaultBindings}
|
bindings={defaultBindings}
|
||||||
jsImports={imports}
|
jsImports={imports}
|
||||||
showSummary={vars.showSummary}
|
showSummary={vars.showSummary}
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -421,7 +428,7 @@ let SquigglePlayground: FC<PlaygroundProps> = ({
|
||||||
};
|
};
|
||||||
export default SquigglePlayground;
|
export default SquigglePlayground;
|
||||||
export function renderSquigglePlaygroundToDom(props: PlaygroundProps) {
|
export function renderSquigglePlaygroundToDom(props: PlaygroundProps) {
|
||||||
let parent = document.createElement("div");
|
const parent = document.createElement("div");
|
||||||
ReactDOM.render(<SquigglePlayground {...props} />, parent);
|
ReactDOM.render(<SquigglePlayground {...props} />, parent);
|
||||||
return parent;
|
return parent;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,9 @@ export {
|
||||||
renderSquiggleEditorToDom,
|
renderSquiggleEditorToDom,
|
||||||
renderSquigglePartialToDom,
|
renderSquigglePartialToDom,
|
||||||
} from "./components/SquiggleEditor";
|
} from "./components/SquiggleEditor";
|
||||||
import SquigglePlayground, {
|
export {
|
||||||
|
default as SquigglePlayground,
|
||||||
renderSquigglePlaygroundToDom,
|
renderSquigglePlaygroundToDom,
|
||||||
} from "./components/SquigglePlayground";
|
} from "./components/SquigglePlayground";
|
||||||
export { SquigglePlayground, renderSquigglePlaygroundToDom };
|
|
||||||
|
|
||||||
export { mergeBindings } from "@quri/squiggle-lang";
|
export { mergeBindings } from "@quri/squiggle-lang";
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
{"version":3,"file":"SquiggleChart.stories.js","sourceRoot":"","sources":["SquiggleChart.stories.tsx"],"names":[],"mappings":";;;AAAA,6BAA8B;AAC9B,iDAA+C;AAG/C,qBAAe;IACb,KAAK,EAAE,uBAAuB;IAC9B,SAAS,EAAE,6BAAa;CACzB,CAAA;AAED,IAAM,QAAQ,GAAG,UAAC,EAAgB;QAAf,cAAc,oBAAA;IAAM,OAAA,oBAAC,6BAAa,IAAC,cAAc,EAAE,cAAc,GAAI;AAAjD,CAAiD,CAAA;AAE3E,QAAA,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;AACxC,eAAO,CAAC,IAAI,GAAG;IACb,cAAc,EAAE,cAAc;CAC/B,CAAC"}
|
|
|
@ -1,24 +1,26 @@
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
|
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
mode: "production",
|
mode: "production",
|
||||||
devtool: "source-map",
|
devtool: "source-map",
|
||||||
profile: true,
|
profile: true,
|
||||||
entry: "./src/index.ts",
|
entry: ["./src/index.ts", "./src/tailwind.css"],
|
||||||
module: {
|
module: {
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
test: /\.tsx?$/,
|
test: /\.tsx?$/,
|
||||||
loader: "ts-loader",
|
loader: "ts-loader",
|
||||||
options: { projectReferences: true, transpileOnly: true },
|
options: { projectReferences: true },
|
||||||
exclude: /node_modules/,
|
exclude: /node_modules/,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.css$/i,
|
test: /\.css$/i,
|
||||||
use: ["style-loader", "css-loader"],
|
use: [MiniCssExtractPlugin.loader, "css-loader", "postcss-loader"],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
plugins: [new MiniCssExtractPlugin()],
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: [".js", ".tsx", ".ts"],
|
extensions: [".js", ".tsx", ".ts"],
|
||||||
alias: {
|
alias: {
|
||||||
|
|
|
@ -232,6 +232,7 @@ describe("Peggy parse", () => {
|
||||||
})
|
})
|
||||||
describe("unit", () => {
|
describe("unit", () => {
|
||||||
testParse("1m", "{(::fromUnit_m 1)}")
|
testParse("1m", "{(::fromUnit_m 1)}")
|
||||||
|
testParse("1M", "{(::fromUnit_M 1)}")
|
||||||
testParse("1m+2cm", "{(::add (::fromUnit_m 1) (::fromUnit_cm 2))}")
|
testParse("1m+2cm", "{(::add (::fromUnit_m 1) (::fromUnit_cm 2))}")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -56,14 +56,14 @@
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"moduleserve": "^0.9.1",
|
"moduleserve": "^0.9.1",
|
||||||
"nyc": "^15.1.0",
|
"nyc": "^15.1.0",
|
||||||
"peggy": "^2.0.0",
|
"peggy": "^2.0.1",
|
||||||
"reanalyze": "^2.22.0",
|
"reanalyze": "^2.22.0",
|
||||||
"rescript-fast-check": "^1.1.1",
|
"rescript-fast-check": "^1.1.1",
|
||||||
"ts-jest": "^27.1.4",
|
"ts-jest": "^27.1.4",
|
||||||
"ts-loader": "^9.3.0",
|
"ts-loader": "^9.3.0",
|
||||||
"ts-node": "^10.8.0",
|
"ts-node": "^10.8.1",
|
||||||
"typescript": "^4.7.2",
|
"typescript": "^4.7.3",
|
||||||
"webpack": "^5.72.1",
|
"webpack": "^5.73.0",
|
||||||
"webpack-cli": "^4.9.2"
|
"webpack-cli": "^4.9.2"
|
||||||
},
|
},
|
||||||
"source": "./src/js/index.ts",
|
"source": "./src/js/index.ts",
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {
|
||||||
import { result, resultMap, Ok } from "./types";
|
import { result, resultMap, Ok } from "./types";
|
||||||
import {
|
import {
|
||||||
Constructors_mean,
|
Constructors_mean,
|
||||||
|
Constructors_stdev,
|
||||||
Constructors_sample,
|
Constructors_sample,
|
||||||
Constructors_pdf,
|
Constructors_pdf,
|
||||||
Constructors_cdf,
|
Constructors_cdf,
|
||||||
|
@ -69,6 +70,10 @@ export class Distribution {
|
||||||
return Constructors_mean({ env: this.env }, this.t);
|
return Constructors_mean({ env: this.env }, this.t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stdev(): result<number, distributionError> {
|
||||||
|
return Constructors_stdev({ env: this.env }, this.t);
|
||||||
|
}
|
||||||
|
|
||||||
sample(): result<number, distributionError> {
|
sample(): result<number, distributionError> {
|
||||||
return Constructors_sample({ env: this.env }, this.t);
|
return Constructors_sample({ env: this.env }, this.t);
|
||||||
}
|
}
|
||||||
|
|
|
@ -265,6 +265,8 @@ module Constructors = {
|
||||||
module C = DistributionTypes.Constructors.UsingDists
|
module C = DistributionTypes.Constructors.UsingDists
|
||||||
open OutputLocal
|
open OutputLocal
|
||||||
let mean = (~env, dist) => C.mean(dist)->run(~env)->toFloatR
|
let mean = (~env, dist) => C.mean(dist)->run(~env)->toFloatR
|
||||||
|
let stdev = (~env, dist) => C.stdev(dist)->run(~env)->toFloatR
|
||||||
|
let variance = (~env, dist) => C.variance(dist)->run(~env)->toFloatR
|
||||||
let sample = (~env, dist) => C.sample(dist)->run(~env)->toFloatR
|
let sample = (~env, dist) => C.sample(dist)->run(~env)->toFloatR
|
||||||
let cdf = (~env, dist, f) => C.cdf(dist, f)->run(~env)->toFloatR
|
let cdf = (~env, dist, f) => C.cdf(dist, f)->run(~env)->toFloatR
|
||||||
let inv = (~env, dist, f) => C.inv(dist, f)->run(~env)->toFloatR
|
let inv = (~env, dist, f) => C.inv(dist, f)->run(~env)->toFloatR
|
||||||
|
|
|
@ -49,6 +49,10 @@ module Constructors: {
|
||||||
@genType
|
@genType
|
||||||
let mean: (~env: env, genericDist) => result<float, error>
|
let mean: (~env: env, genericDist) => result<float, error>
|
||||||
@genType
|
@genType
|
||||||
|
let stdev: (~env: env, genericDist) => result<float, error>
|
||||||
|
@genType
|
||||||
|
let variance: (~env: env, genericDist) => result<float, error>
|
||||||
|
@genType
|
||||||
let sample: (~env: env, genericDist) => result<float, error>
|
let sample: (~env: env, genericDist) => result<float, error>
|
||||||
@genType
|
@genType
|
||||||
let cdf: (~env: env, genericDist, float) => result<float, error>
|
let cdf: (~env: env, genericDist, float) => result<float, error>
|
||||||
|
|
|
@ -30,9 +30,9 @@ module Error = {
|
||||||
@genType
|
@genType
|
||||||
let toString = (err: error): string =>
|
let toString = (err: error): string =>
|
||||||
switch err {
|
switch err {
|
||||||
| NotYetImplemented => "Function Not Yet Implemented"
|
| NotYetImplemented => "Function not yet implemented"
|
||||||
| Unreachable => "Unreachable"
|
| Unreachable => "Unreachable"
|
||||||
| DistributionVerticalShiftIsInvalid => "Distribution Vertical Shift is Invalid"
|
| DistributionVerticalShiftIsInvalid => "Distribution vertical shift is invalid"
|
||||||
| ArgumentError(s) => `Argument Error ${s}`
|
| ArgumentError(s) => `Argument Error ${s}`
|
||||||
| LogarithmOfDistributionError(s) => `Logarithm of input error: ${s}`
|
| LogarithmOfDistributionError(s) => `Logarithm of input error: ${s}`
|
||||||
| SampleSetError(TooFewSamples) => "Too Few Samples"
|
| SampleSetError(TooFewSamples) => "Too Few Samples"
|
||||||
|
@ -68,6 +68,11 @@ module DistributionOperation = {
|
||||||
| #Mean
|
| #Mean
|
||||||
| #Sample
|
| #Sample
|
||||||
| #IntegralSum
|
| #IntegralSum
|
||||||
|
| #Mode
|
||||||
|
| #Stdev
|
||||||
|
| #Min
|
||||||
|
| #Max
|
||||||
|
| #Variance
|
||||||
]
|
]
|
||||||
|
|
||||||
type toScaleFn = [
|
type toScaleFn = [
|
||||||
|
@ -117,6 +122,11 @@ module DistributionOperation = {
|
||||||
| ToFloat(#Cdf(r)) => `cdf(${E.Float.toFixed(r)})`
|
| ToFloat(#Cdf(r)) => `cdf(${E.Float.toFixed(r)})`
|
||||||
| ToFloat(#Inv(r)) => `inv(${E.Float.toFixed(r)})`
|
| ToFloat(#Inv(r)) => `inv(${E.Float.toFixed(r)})`
|
||||||
| ToFloat(#Mean) => `mean`
|
| ToFloat(#Mean) => `mean`
|
||||||
|
| ToFloat(#Min) => `min`
|
||||||
|
| ToFloat(#Max) => `max`
|
||||||
|
| ToFloat(#Stdev) => `stdev`
|
||||||
|
| ToFloat(#Variance) => `variance`
|
||||||
|
| ToFloat(#Mode) => `mode`
|
||||||
| ToFloat(#Pdf(r)) => `pdf(${E.Float.toFixed(r)})`
|
| ToFloat(#Pdf(r)) => `pdf(${E.Float.toFixed(r)})`
|
||||||
| ToFloat(#Sample) => `sample`
|
| ToFloat(#Sample) => `sample`
|
||||||
| ToFloat(#IntegralSum) => `integralSum`
|
| ToFloat(#IntegralSum) => `integralSum`
|
||||||
|
@ -151,6 +161,8 @@ module Constructors = {
|
||||||
module UsingDists = {
|
module UsingDists = {
|
||||||
@genType
|
@genType
|
||||||
let mean = (dist): t => FromDist(ToFloat(#Mean), dist)
|
let mean = (dist): t => FromDist(ToFloat(#Mean), dist)
|
||||||
|
let stdev = (dist): t => FromDist(ToFloat(#Stdev), dist)
|
||||||
|
let variance = (dist): t => FromDist(ToFloat(#Variance), dist)
|
||||||
let sample = (dist): t => FromDist(ToFloat(#Sample), dist)
|
let sample = (dist): t => FromDist(ToFloat(#Sample), dist)
|
||||||
let cdf = (dist, x): t => FromDist(ToFloat(#Cdf(x)), dist)
|
let cdf = (dist, x): t => FromDist(ToFloat(#Cdf(x)), dist)
|
||||||
let inv = (dist, x): t => FromDist(ToFloat(#Inv(x)), dist)
|
let inv = (dist, x): t => FromDist(ToFloat(#Inv(x)), dist)
|
||||||
|
|
|
@ -108,7 +108,7 @@ let toFloatOperation = (
|
||||||
) => {
|
) => {
|
||||||
switch distToFloatOperation {
|
switch distToFloatOperation {
|
||||||
| #IntegralSum => Ok(integralEndY(t))
|
| #IntegralSum => Ok(integralEndY(t))
|
||||||
| (#Pdf(_) | #Cdf(_) | #Inv(_) | #Mean | #Sample) as op => {
|
| (#Pdf(_) | #Cdf(_) | #Inv(_) | #Mean | #Sample | #Min | #Max) as op => {
|
||||||
let trySymbolicSolution = switch (t: t) {
|
let trySymbolicSolution = switch (t: t) {
|
||||||
| Symbolic(r) => SymbolicDist.T.operate(op, r)->E.R.toOption
|
| Symbolic(r) => SymbolicDist.T.operate(op, r)->E.R.toOption
|
||||||
| _ => None
|
| _ => None
|
||||||
|
@ -118,6 +118,8 @@ let toFloatOperation = (
|
||||||
| (SampleSet(sampleSet), #Mean) => SampleSetDist.mean(sampleSet)->Some
|
| (SampleSet(sampleSet), #Mean) => SampleSetDist.mean(sampleSet)->Some
|
||||||
| (SampleSet(sampleSet), #Sample) => SampleSetDist.sample(sampleSet)->Some
|
| (SampleSet(sampleSet), #Sample) => SampleSetDist.sample(sampleSet)->Some
|
||||||
| (SampleSet(sampleSet), #Inv(r)) => SampleSetDist.percentile(sampleSet, r)->Some
|
| (SampleSet(sampleSet), #Inv(r)) => SampleSetDist.percentile(sampleSet, r)->Some
|
||||||
|
| (SampleSet(sampleSet), #Min) => SampleSetDist.min(sampleSet)->Some
|
||||||
|
| (SampleSet(sampleSet), #Max) => SampleSetDist.max(sampleSet)->Some
|
||||||
| _ => None
|
| _ => None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,6 +132,16 @@ let toFloatOperation = (
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
| (#Stdev | #Variance | #Mode) as op =>
|
||||||
|
switch t {
|
||||||
|
| SampleSet(s) =>
|
||||||
|
switch op {
|
||||||
|
| #Stdev => SampleSetDist.stdev(s)->Ok
|
||||||
|
| #Variance => SampleSetDist.variance(s)->Ok
|
||||||
|
| #Mode => SampleSetDist.mode(s)->Ok
|
||||||
|
}
|
||||||
|
| _ => Error(DistributionTypes.NotYetImplemented)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -254,6 +254,8 @@ let operate = (distToFloatOp: Operation.distToFloatOperation, s): float =>
|
||||||
| #Inv(f) => inv(f, s)
|
| #Inv(f) => inv(f, s)
|
||||||
| #Sample => sample(s)
|
| #Sample => sample(s)
|
||||||
| #Mean => T.mean(s)
|
| #Mean => T.mean(s)
|
||||||
|
| #Min => T.minX(s)
|
||||||
|
| #Max => T.maxX(s)
|
||||||
}
|
}
|
||||||
|
|
||||||
let toSparkline = (t: t, bucketCount): result<string, PointSetTypes.sparklineError> =>
|
let toSparkline = (t: t, bucketCount): result<string, PointSetTypes.sparklineError> =>
|
||||||
|
|
|
@ -449,6 +449,8 @@ module T = {
|
||||||
| #Cdf(f) => Ok(cdf(f, s))
|
| #Cdf(f) => Ok(cdf(f, s))
|
||||||
| #Pdf(f) => Ok(pdf(f, s))
|
| #Pdf(f) => Ok(pdf(f, s))
|
||||||
| #Inv(f) => Ok(inv(f, s))
|
| #Inv(f) => Ok(inv(f, s))
|
||||||
|
| #Min => Ok(min(s))
|
||||||
|
| #Max => Ok(max(s))
|
||||||
| #Sample => Ok(sample(s))
|
| #Sample => Ok(sample(s))
|
||||||
| #Mean => mean(s)
|
| #Mean => mean(s)
|
||||||
}
|
}
|
||||||
|
|
|
@ -264,6 +264,9 @@ basicLiteral
|
||||||
identifier 'identifier'
|
identifier 'identifier'
|
||||||
= ([_a-z]+[_a-z0-9]i*) {return nodeIdentifier(text())}
|
= ([_a-z]+[_a-z0-9]i*) {return nodeIdentifier(text())}
|
||||||
|
|
||||||
|
unitIdentifier 'identifier'
|
||||||
|
= ([_a-zA-Z]+[_a-z0-9]i*) {return nodeIdentifier(text())}
|
||||||
|
|
||||||
dollarIdentifier '$identifier'
|
dollarIdentifier '$identifier'
|
||||||
= ([\$_a-z]+[\$_a-z0-9]i*) {return nodeIdentifier(text())}
|
= ([\$_a-z]+[\$_a-z0-9]i*) {return nodeIdentifier(text())}
|
||||||
|
|
||||||
|
@ -271,7 +274,7 @@ string 'string'
|
||||||
= characters:("'" @([^'])* "'") {return nodeString(characters.join(''))}
|
= characters:("'" @([^'])* "'") {return nodeString(characters.join(''))}
|
||||||
/ characters:('"' @([^"])* '"') {return nodeString(characters.join(''))}
|
/ characters:('"' @([^"])* '"') {return nodeString(characters.join(''))}
|
||||||
|
|
||||||
number = number:(float / integer) unit:identifier?
|
number = number:(float / integer) unit:unitIdentifier?
|
||||||
{
|
{
|
||||||
if (unit === null)
|
if (unit === null)
|
||||||
{ return number }
|
{ return number }
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
module EV = ReducerInterface_ExpressionValue
|
||||||
|
type expressionValue = EV.expressionValue
|
||||||
|
|
||||||
|
let dispatch = (call: EV.functionCall, _: DistributionOperation.env): option<
|
||||||
|
result<expressionValue, QuriSquiggleLang.Reducer_ErrorValue.errorValue>,
|
||||||
|
> => {
|
||||||
|
switch call {
|
||||||
|
| ("toString", [EvDate(t)]) => EV.EvString(DateTime.Date.toString(t))->Ok->Some
|
||||||
|
| ("makeDateFromYear", [EvNumber(year)]) =>
|
||||||
|
switch DateTime.Date.makeFromYear(year) {
|
||||||
|
| Ok(t) => EV.EvDate(t)->Ok->Some
|
||||||
|
| Error(e) => Reducer_ErrorValue.RETodo(e)->Error->Some
|
||||||
|
}
|
||||||
|
| ("dateFromNumber", [EvNumber(f)]) => EV.EvDate(DateTime.Date.fromFloat(f))->Ok->Some
|
||||||
|
| ("toNumber", [EvDate(f)]) => EV.EvNumber(DateTime.Date.toFloat(f))->Ok->Some
|
||||||
|
| ("subtract", [EvDate(d1), EvDate(d2)]) =>
|
||||||
|
switch DateTime.Date.subtract(d1, d2) {
|
||||||
|
| Ok(d) => EV.EvTimeDuration(d)->Ok
|
||||||
|
| Error(e) => Error(RETodo(e))
|
||||||
|
}->Some
|
||||||
|
| ("subtract", [EvDate(d1), EvTimeDuration(d2)]) =>
|
||||||
|
EV.EvDate(DateTime.Date.subtractDuration(d1, d2))->Ok->Some
|
||||||
|
| ("add", [EvDate(d1), EvTimeDuration(d2)]) =>
|
||||||
|
EV.EvDate(DateTime.Date.addDuration(d1, d2))->Ok->Some
|
||||||
|
| _ => None
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,32 +1,7 @@
|
||||||
module EV = ReducerInterface_ExpressionValue
|
module EV = ReducerInterface_ExpressionValue
|
||||||
type expressionValue = EV.expressionValue
|
type expressionValue = EV.expressionValue
|
||||||
|
|
||||||
let dateDispatch = (call: EV.functionCall, _: DistributionOperation.env): option<
|
let dispatch = (call: EV.functionCall, _: DistributionOperation.env): option<
|
||||||
result<expressionValue, QuriSquiggleLang.Reducer_ErrorValue.errorValue>,
|
|
||||||
> => {
|
|
||||||
switch call {
|
|
||||||
| ("toString", [EvDate(t)]) => EV.EvString(DateTime.Date.toString(t))->Ok->Some
|
|
||||||
| ("makeDateFromYear", [EvNumber(year)]) =>
|
|
||||||
switch DateTime.Date.makeFromYear(year) {
|
|
||||||
| Ok(t) => EV.EvDate(t)->Ok->Some
|
|
||||||
| Error(e) => Reducer_ErrorValue.RETodo(e)->Error->Some
|
|
||||||
}
|
|
||||||
| ("dateFromNumber", [EvNumber(f)]) => EV.EvDate(DateTime.Date.fromFloat(f))->Ok->Some
|
|
||||||
| ("toNumber", [EvDate(f)]) => EV.EvNumber(DateTime.Date.toFloat(f))->Ok->Some
|
|
||||||
| ("subtract", [EvDate(d1), EvDate(d2)]) =>
|
|
||||||
switch DateTime.Date.subtract(d1, d2) {
|
|
||||||
| Ok(d) => EV.EvTimeDuration(d)->Ok
|
|
||||||
| Error(e) => Error(RETodo(e))
|
|
||||||
}->Some
|
|
||||||
| ("subtract", [EvDate(d1), EvTimeDuration(d2)]) =>
|
|
||||||
EV.EvDate(DateTime.Date.subtractDuration(d1, d2))->Ok->Some
|
|
||||||
| ("add", [EvDate(d1), EvTimeDuration(d2)]) =>
|
|
||||||
EV.EvDate(DateTime.Date.addDuration(d1, d2))->Ok->Some
|
|
||||||
| _ => None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let durationDispatch = (call: EV.functionCall, _: DistributionOperation.env): option<
|
|
||||||
result<expressionValue, QuriSquiggleLang.Reducer_ErrorValue.errorValue>,
|
result<expressionValue, QuriSquiggleLang.Reducer_ErrorValue.errorValue>,
|
||||||
> => {
|
> => {
|
||||||
switch call {
|
switch call {
|
||||||
|
@ -54,17 +29,4 @@ let durationDispatch = (call: EV.functionCall, _: DistributionOperation.env): op
|
||||||
EV.EvTimeDuration(DateTime.Duration.divide(d1, d2))->Ok->Some
|
EV.EvTimeDuration(DateTime.Duration.divide(d1, d2))->Ok->Some
|
||||||
| _ => None
|
| _ => None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let dispatch = (call: EV.functionCall, env: DistributionOperation.env): option<
|
|
||||||
result<expressionValue, QuriSquiggleLang.Reducer_ErrorValue.errorValue>,
|
|
||||||
> => {
|
|
||||||
switch dateDispatch(call, env) {
|
|
||||||
| Some(r) => Some(r)
|
|
||||||
| None =>
|
|
||||||
switch durationDispatch(call, env) {
|
|
||||||
| Some(r) => Some(r)
|
|
||||||
| None => None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -14,15 +14,27 @@ type expressionValue = ExpressionValue.expressionValue
|
||||||
Map external calls of Reducer
|
Map external calls of Reducer
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// I expect that it's important to build this first, so it doesn't get recalculated for each tryRegistry() call.
|
||||||
|
let registry = FunctionRegistry_Library.registry
|
||||||
|
|
||||||
|
let tryRegistry = ((fnName, args): ExpressionValue.functionCall, env) => {
|
||||||
|
FunctionRegistry_Core.Registry.matchAndRun(~registry, ~fnName, ~args, ~env)->E.O2.fmap(
|
||||||
|
E.R2.errMap(_, s => Reducer_ErrorValue.RETodo(s)),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
let dispatch = (call: ExpressionValue.functionCall, environment, chain): result<
|
let dispatch = (call: ExpressionValue.functionCall, environment, chain): result<
|
||||||
expressionValue,
|
expressionValue,
|
||||||
'e,
|
'e,
|
||||||
> =>
|
> => {
|
||||||
switch ReducerInterface_GenericDistribution.dispatch(call, environment) {
|
E.A.O.firstSomeFn([
|
||||||
| Some(r) => r
|
() => ReducerInterface_GenericDistribution.dispatch(call, environment),
|
||||||
| None =>
|
() => ReducerInterface_Date.dispatch(call, environment),
|
||||||
ReducerInterface_DateTime.dispatch(call, environment) |> E.O.default(chain(call, environment))
|
() => ReducerInterface_Duration.dispatch(call, environment),
|
||||||
}
|
() => ReducerInterface_Number.dispatch(call, environment),
|
||||||
|
() => tryRegistry(call, environment),
|
||||||
|
])->E.O2.default(chain(call, environment))
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
If your dispatch is too big you can divide it into smaller dispatches and pass the call so that it gets called finally.
|
If your dispatch is too big you can divide it into smaller dispatches and pass the call so that it gets called finally.
|
||||||
|
|
||||||
|
|
|
@ -209,7 +209,18 @@ let dispatchToGenericOutput = (
|
||||||
| ("sample", [EvDistribution(dist)]) => Helpers.toFloatFn(#Sample, dist, ~env)
|
| ("sample", [EvDistribution(dist)]) => Helpers.toFloatFn(#Sample, dist, ~env)
|
||||||
| ("sampleN", [EvDistribution(dist), EvNumber(n)]) =>
|
| ("sampleN", [EvDistribution(dist), EvNumber(n)]) =>
|
||||||
Some(FloatArray(GenericDist.sampleN(dist, Belt.Int.fromFloat(n))))
|
Some(FloatArray(GenericDist.sampleN(dist, Belt.Int.fromFloat(n))))
|
||||||
| ("mean", [EvDistribution(dist)]) => Helpers.toFloatFn(#Mean, dist, ~env)
|
| (("mean" | "stdev" | "variance" | "min" | "max" | "mode") as op, [EvDistribution(dist)]) => {
|
||||||
|
let fn = switch op {
|
||||||
|
| "mean" => #Mean
|
||||||
|
| "stdev" => #Stdev
|
||||||
|
| "variance" => #Variance
|
||||||
|
| "min" => #Min
|
||||||
|
| "max" => #Max
|
||||||
|
| "mode" => #Mode
|
||||||
|
| _ => #Mean
|
||||||
|
}
|
||||||
|
Helpers.toFloatFn(fn, dist, ~env)
|
||||||
|
}
|
||||||
| ("integralSum", [EvDistribution(dist)]) => Helpers.toFloatFn(#IntegralSum, dist, ~env)
|
| ("integralSum", [EvDistribution(dist)]) => Helpers.toFloatFn(#IntegralSum, dist, ~env)
|
||||||
| ("toString", [EvDistribution(dist)]) => Helpers.toStringFn(ToString, dist, ~env)
|
| ("toString", [EvDistribution(dist)]) => Helpers.toStringFn(ToString, dist, ~env)
|
||||||
| ("toSparkline", [EvDistribution(dist)]) =>
|
| ("toSparkline", [EvDistribution(dist)]) =>
|
||||||
|
@ -350,20 +361,5 @@ let genericOutputToReducerValue = (o: DistributionOperation.outputType): result<
|
||||||
| GenDistError(err) => Error(REDistributionError(err))
|
| GenDistError(err) => Error(REDistributionError(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
// I expect that it's important to build this first, so it doesn't get recalculated for each tryRegistry() call.
|
let dispatch = (call: ExpressionValue.functionCall, environment) =>
|
||||||
let registry = FunctionRegistry_Library.registry
|
dispatchToGenericOutput(call, environment)->E.O2.fmap(genericOutputToReducerValue)
|
||||||
|
|
||||||
let tryRegistry = ((fnName, args): ExpressionValue.functionCall, env) => {
|
|
||||||
FunctionRegistry_Core.Registry.matchAndRun(~registry, ~fnName, ~args, ~env)->E.O2.fmap(
|
|
||||||
E.R2.errMap(_, s => Reducer_ErrorValue.RETodo(s)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
let dispatch = (call: ExpressionValue.functionCall, environment) => {
|
|
||||||
let regularDispatch =
|
|
||||||
dispatchToGenericOutput(call, environment)->E.O2.fmap(genericOutputToReducerValue)
|
|
||||||
switch regularDispatch {
|
|
||||||
| Some(x) => Some(x)
|
|
||||||
| None => tryRegistry(call, environment)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
module EV = ReducerInterface_ExpressionValue
|
||||||
|
type expressionValue = EV.expressionValue
|
||||||
|
|
||||||
|
module ScientificUnit = {
|
||||||
|
let nameToMultiplier = str =>
|
||||||
|
switch str {
|
||||||
|
| "n" => Some(1E-9)
|
||||||
|
| "m" => Some(1E-3)
|
||||||
|
| "k" => Some(1E3)
|
||||||
|
| "M" => Some(1E6)
|
||||||
|
| "B" => Some(1E9)
|
||||||
|
| "G" => Some(1E9)
|
||||||
|
| "T" => Some(1E12)
|
||||||
|
| "P" => Some(1E15)
|
||||||
|
| _ => None
|
||||||
|
}
|
||||||
|
|
||||||
|
let getMultiplier = (r: string) => {
|
||||||
|
let match = Js.String2.match_(r, %re(`/fromUnit_([_a-zA-Z]*)/`))
|
||||||
|
switch match {
|
||||||
|
| Some([_, unit]) => nameToMultiplier(unit)
|
||||||
|
| _ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let dispatch = (call: EV.functionCall, _: DistributionOperation.env): option<
|
||||||
|
result<expressionValue, QuriSquiggleLang.Reducer_ErrorValue.errorValue>,
|
||||||
|
> => {
|
||||||
|
switch call {
|
||||||
|
| (
|
||||||
|
("fromUnit_n"
|
||||||
|
| "fromUnit_m"
|
||||||
|
| "fromUnit_k"
|
||||||
|
| "fromUnit_M"
|
||||||
|
| "fromUnit_B"
|
||||||
|
| "fromUnit_G"
|
||||||
|
| "fromUnit_T"
|
||||||
|
| "fromUnit_P") as op,
|
||||||
|
[EvNumber(f)],
|
||||||
|
) =>
|
||||||
|
op->ScientificUnit.getMultiplier->E.O2.fmap(multiplier => EV.EvNumber(f *. multiplier)->Ok)
|
||||||
|
| _ => None
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,6 +26,8 @@ type distToFloatOperation = [
|
||||||
| #Inv(float)
|
| #Inv(float)
|
||||||
| #Mean
|
| #Mean
|
||||||
| #Sample
|
| #Sample
|
||||||
|
| #Min
|
||||||
|
| #Max
|
||||||
]
|
]
|
||||||
|
|
||||||
module Convolution = {
|
module Convolution = {
|
||||||
|
|
|
@ -19,27 +19,7 @@ const config = {
|
||||||
organizationName: "quantified-uncertainty", // Usually your GitHub org/user name.
|
organizationName: "quantified-uncertainty", // Usually your GitHub org/user name.
|
||||||
projectName: "squiggle", // Usually your repo name.
|
projectName: "squiggle", // Usually your repo name.
|
||||||
|
|
||||||
plugins: [
|
plugins: [],
|
||||||
"docusaurus-tailwindcss",
|
|
||||||
() => ({
|
|
||||||
configureWebpack(config, isServer, utils, content) {
|
|
||||||
return {
|
|
||||||
resolve: {
|
|
||||||
alias: {
|
|
||||||
"@quri/squiggle-components": path.resolve(
|
|
||||||
__dirname,
|
|
||||||
"../components/src"
|
|
||||||
),
|
|
||||||
"@quri/squiggle-lang": path.resolve(
|
|
||||||
__dirname,
|
|
||||||
"../squiggle-lang/src/js"
|
|
||||||
),
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
|
|
||||||
presets: [
|
presets: [
|
||||||
[
|
[
|
||||||
|
@ -61,7 +41,10 @@ const config = {
|
||||||
"https://github.com/quantified-uncertainty/squiggle/tree/develop/packages/website/",
|
"https://github.com/quantified-uncertainty/squiggle/tree/develop/packages/website/",
|
||||||
},
|
},
|
||||||
theme: {
|
theme: {
|
||||||
customCss: require.resolve("./src/css/custom.css"),
|
customCss: [
|
||||||
|
require.resolve("./src/css/custom.css"),
|
||||||
|
require.resolve("@quri/squiggle-components/dist/main.css"),
|
||||||
|
],
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[build]
|
[build]
|
||||||
base = "packages/website/"
|
base = "packages/website/"
|
||||||
command = "cd ../squiggle-lang && yarn build && cd ../website && yarn build"
|
command = "cd ../squiggle-lang && yarn build && cd ../components && yarn build && cd ../website && yarn build"
|
||||||
publish = "build/"
|
publish = "build/"
|
||||||
ignore = "node -e 'process.exitCode = process.env.BRANCH.includes(\"dependabot\") ? 0 : 1' && git diff --quiet $CACHED_COMMIT_REF $COMMIT_REF ../"
|
ignore = "node -e 'process.exitCode = process.env.BRANCH.includes(\"dependabot\") ? 0 : 1' && git diff --quiet $CACHED_COMMIT_REF $COMMIT_REF ../"
|
||||||
|
|
||||||
|
|
|
@ -4,10 +4,6 @@
|
||||||
* work well for content-centric websites.
|
* work well for content-centric websites.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@tailwind base;
|
|
||||||
@tailwind components;
|
|
||||||
@tailwind utilities;
|
|
||||||
|
|
||||||
/* You can override the default Infima variables here. */
|
/* You can override the default Infima variables here. */
|
||||||
:root {
|
:root {
|
||||||
--ifm-color-primary: #2488df;
|
--ifm-color-primary: #2488df;
|
||||||
|
|
7
packages/website/tailwind.config.js
Normal file
7
packages/website/tailwind.config.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
module.exports = {
|
||||||
|
content: ["./src/**/*.{html,tsx,ts,js,jsx}"],
|
||||||
|
theme: {
|
||||||
|
extend: {},
|
||||||
|
},
|
||||||
|
plugins: [require("@tailwindcss/forms")],
|
||||||
|
};
|
1
packages/website/webpack.config.js
Normal file
1
packages/website/webpack.config.js
Normal file
|
@ -0,0 +1 @@
|
||||||
|
module.exports = {};
|
Loading…
Reference in New Issue
Block a user