Compare commits
1 Commits
develop
...
bindings-r
Author | SHA1 | Date | |
---|---|---|---|
|
d4025e7f02 |
20
.github/CODEOWNERS
vendored
20
.github/CODEOWNERS
vendored
|
@ -9,22 +9,22 @@
|
|||
# This also holds true for GitHub teams.
|
||||
|
||||
# Rescript
|
||||
*.res @berekuk @OAGr
|
||||
*.resi @berekuk @OAGr
|
||||
*.res @OAGr @quinn-dougherty
|
||||
*.resi @OAGr @quinn-dougherty
|
||||
|
||||
# Typescript
|
||||
*.tsx @Hazelfire @berekuk @OAGr
|
||||
*.ts @Hazelfire @berekuk @OAGr
|
||||
*.tsx @Hazelfire @OAGr
|
||||
*.ts @Hazelfire @OAGr
|
||||
|
||||
# Javascript
|
||||
*.js @Hazelfire @berekuk @OAGr
|
||||
*.js @Hazelfire @OAGr
|
||||
|
||||
# Any opsy files
|
||||
.github/** @quinn-dougherty @berekuk @OAGr
|
||||
*.json @quinn-dougherty @Hazelfire @berekuk @OAGr
|
||||
*.y*ml @quinn-dougherty @berekuk @OAGr
|
||||
*.config.js @Hazelfire @berekuk @OAGr
|
||||
vercel.json @OAGr @berekuk @Hazelfire
|
||||
.github/** @quinn-dougherty @OAGr
|
||||
*.json @quinn-dougherty @Hazelfire @OAGr
|
||||
*.y*ml @quinn-dougherty @OAGr
|
||||
*.config.js @Hazelfire @OAGr
|
||||
netlify.toml @quinn-dougherty @OAGr @Hazelfire
|
||||
|
||||
# Documentation
|
||||
*.md @quinn-dougherty @OAGr @Hazelfire
|
||||
|
|
13
.github/dependabot.yml
vendored
13
.github/dependabot.yml
vendored
|
@ -8,17 +8,6 @@ updates:
|
|||
- package-ecosystem: "npm" # See documentation for possible values
|
||||
directory: "/" # Location of package manifests
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
interval: "daily"
|
||||
commit-message:
|
||||
prefix: "⬆️"
|
||||
open-pull-requests-limit: 100
|
||||
labels:
|
||||
- "dependencies"
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
commit-message:
|
||||
prefix: "⬆️"
|
||||
labels:
|
||||
- "dependencies"
|
||||
|
|
87
.github/workflows/ci-cachix.yml
vendored
87
.github/workflows/ci-cachix.yml
vendored
|
@ -1,87 +0,0 @@
|
|||
name: Nix build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
- develop
|
||||
- reducer-dev
|
||||
- epic-reducer-project
|
||||
|
||||
jobs:
|
||||
flake-lints:
|
||||
name: All lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
- name: Install nix
|
||||
uses: cachix/install-nix-action@v17
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-22.05
|
||||
- name: Use cachix
|
||||
uses: cachix/cachix-action@v10
|
||||
with:
|
||||
name: quantified-uncertainty
|
||||
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||
|
||||
- name: Check that lang lints
|
||||
run: nix build .#lang-lint
|
||||
- name: Check that components lints
|
||||
run: nix build .#components-lint
|
||||
- name: Check that website lints
|
||||
run: nix build .#docusaurus-lint
|
||||
- name: Check that vscode extension lints
|
||||
run: nix build .#vscode-lint
|
||||
- name: Check that cli lints
|
||||
run: nix build .#cli-lint
|
||||
|
||||
flake-packages:
|
||||
name: Builds, tests, and bundles
|
||||
runs-on: ubuntu-latest
|
||||
needs: flake-lints
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
- name: Install nix
|
||||
uses: cachix/install-nix-action@v17
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-22.05
|
||||
- name: Use cachix
|
||||
uses: cachix/cachix-action@v10
|
||||
with:
|
||||
name: quantified-uncertainty
|
||||
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||
|
||||
- name: Check all lang tests
|
||||
run: nix build .#lang-test
|
||||
- name: Check that lang bundles
|
||||
run: nix build .#lang-bundle
|
||||
- name: Check that components builds
|
||||
run: nix build .#components
|
||||
- name: Check that components bundles
|
||||
run: nix build .#components-bundle
|
||||
|
||||
flake-devshells:
|
||||
name: Development shell environment
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v3
|
||||
- name: Install nix
|
||||
uses: cachix/install-nix-action@v17
|
||||
with:
|
||||
nix_path: nixpkgs=channel:nixos-22.05
|
||||
- name: Use cachix
|
||||
uses: cachix/cachix-action@v10
|
||||
with:
|
||||
name: quantified-uncertainty
|
||||
authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
|
||||
- name: Build js devshell
|
||||
run: nix develop .#js --profile just-js
|
||||
- name: Build js & wasm devshell
|
||||
run: nix develop --profile full-shell
|
163
.github/workflows/ci.yml
vendored
163
.github/workflows/ci.yml
vendored
|
@ -1,4 +1,4 @@
|
|||
name: Squiggle packages checks
|
||||
name: Squiggle packages check
|
||||
|
||||
on:
|
||||
push:
|
||||
|
@ -10,39 +10,146 @@ on:
|
|||
- master
|
||||
- develop
|
||||
|
||||
env:
|
||||
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
|
||||
TURBO_TEAM: quantified-uncertainty
|
||||
|
||||
jobs:
|
||||
build-test-lint:
|
||||
name: Build, test, lint
|
||||
pre_check:
|
||||
name: Precheck for skipping redundant jobs
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
should_skip_lang: ${{ steps.skip_lang_check.outputs.should_skip }}
|
||||
should_skip_components: ${{ steps.skip_components_check.outputs.should_skip }}
|
||||
should_skip_website: ${{ steps.skip_website_check.outputs.should_skip }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Setup Node.js environment
|
||||
uses: actions/setup-node@v3
|
||||
- id: skip_lang_check
|
||||
name: Check if the changes are about squiggle-lang src files
|
||||
uses: fkirc/skip-duplicate-actions@v3.4.1
|
||||
with:
|
||||
node-version: 16
|
||||
cache: 'yarn'
|
||||
- name: Install dependencies
|
||||
run: yarn --frozen-lockfile
|
||||
- name: Turbo run
|
||||
run: npx turbo run build test lint bundle
|
||||
paths: '["packages/squiggle-lang/**"]'
|
||||
- id: skip_components_check
|
||||
name: Check if the changes are about components src files
|
||||
uses: fkirc/skip-duplicate-actions@v3.4.1
|
||||
with:
|
||||
paths: '["packages/components/**"]'
|
||||
- id: skip_website_check
|
||||
name: Check if the changes are about website src files
|
||||
uses: fkirc/skip-duplicate-actions@v3.4.1
|
||||
with:
|
||||
paths: '["packages/website/**"]'
|
||||
|
||||
coverage:
|
||||
name: Coverage
|
||||
lang-lint:
|
||||
name: Language lint
|
||||
runs-on: ubuntu-latest
|
||||
needs: pre_check
|
||||
if: ${{ needs.pre_check.outputs.should_skip_lang != 'true' }}
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
working-directory: packages/squiggle-lang
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install Dependencies
|
||||
run: cd ../../ && yarn
|
||||
- name: Check rescript lint
|
||||
run: yarn lint:rescript
|
||||
- name: Check javascript, typescript, and markdown lint
|
||||
uses: creyD/prettier_action@v4.2
|
||||
with:
|
||||
fetch-depth: 2
|
||||
- name: Setup Node.js environment
|
||||
uses: actions/setup-node@v2
|
||||
dry: true
|
||||
prettier_options: --check packages/squiggle-lang
|
||||
|
||||
lang-build-test-bundle:
|
||||
name: Language build, test, and bundle
|
||||
runs-on: ubuntu-latest
|
||||
needs: pre_check
|
||||
if: ${{ needs.pre_check.outputs.should_skip_lang != 'true' }}
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
working-directory: packages/squiggle-lang
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install dependencies from monorepo level
|
||||
run: cd ../../ && yarn
|
||||
- name: Build rescript codebase
|
||||
run: yarn build
|
||||
- name: Run rescript tests
|
||||
run: yarn test:rescript
|
||||
- name: Run typescript tests
|
||||
run: yarn test:ts
|
||||
- name: Run webpack
|
||||
run: yarn bundle
|
||||
- name: Upload rescript coverage report
|
||||
run: yarn coverage:rescript:ci
|
||||
- name: Upload typescript coverage report
|
||||
run: yarn coverage:ts:ci
|
||||
|
||||
components-lint:
|
||||
name: Components lint
|
||||
runs-on: ubuntu-latest
|
||||
needs: pre_check
|
||||
if: ${{ needs.pre_check.outputs.should_skip_components != 'true' }}
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
working-directory: packages/components
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Check javascript, typescript, and markdown lint
|
||||
uses: creyD/prettier_action@v4.2
|
||||
with:
|
||||
node-version: 16
|
||||
cache: 'yarn'
|
||||
- name: Install dependencies
|
||||
run: yarn
|
||||
- name: Coverage
|
||||
run: npx turbo run coverage
|
||||
dry: true
|
||||
prettier_options: --check packages/components
|
||||
|
||||
components-bundle-build:
|
||||
name: Components bundle and build
|
||||
runs-on: ubuntu-latest
|
||||
needs: pre_check
|
||||
if: ${{ (needs.pre_check.outputs.should_skip_components != 'true') || (needs.pre_check.outputs.should_skip_lang != 'true') }}
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
working-directory: packages/components
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install dependencies from monorepo level
|
||||
run: cd ../../ && yarn
|
||||
- name: Build rescript codebase in squiggle-lang
|
||||
run: cd ../squiggle-lang && yarn build
|
||||
- name: Run webpack
|
||||
run: yarn bundle
|
||||
- name: Build storybook
|
||||
run: yarn build
|
||||
|
||||
website-lint:
|
||||
name: Website lint
|
||||
runs-on: ubuntu-latest
|
||||
needs: pre_check
|
||||
if: ${{ needs.pre_check.outputs.should_skip_website != 'true' }}
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
working-directory: packages/website
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Check javascript, typescript, and markdown lint
|
||||
uses: creyD/prettier_action@v4.2
|
||||
with:
|
||||
dry: true
|
||||
prettier_options: --check packages/website
|
||||
|
||||
website-build:
|
||||
name: Website build
|
||||
runs-on: ubuntu-latest
|
||||
needs: pre_check
|
||||
if: ${{ (needs.pre_check.outputs.should_skip_website != 'true') || (needs.pre_check.outputs.should_skip_lang != 'true') || (needs.pre_check.outputs.should_skip_components != 'true') }}
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
working-directory: packages/website
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Install dependencies from monorepo level
|
||||
run: cd ../../ && yarn
|
||||
- name: Build rescript in squiggle-lang
|
||||
run: cd ../squiggle-lang && yarn build
|
||||
- name: Build website assets
|
||||
run: yarn build
|
||||
|
|
14
.github/workflows/codeql-analysis.yml
vendored
14
.github/workflows/codeql-analysis.yml
vendored
|
@ -12,6 +12,12 @@
|
|||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- production
|
||||
- staging
|
||||
- develop
|
||||
schedule:
|
||||
- cron: "42 19 * * 0"
|
||||
|
||||
|
@ -33,11 +39,11 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
|
@ -48,7 +54,7 @@ jobs:
|
|||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
- name: Install dependencies
|
||||
run: yarn
|
||||
- name: Build rescript
|
||||
|
@ -65,4 +71,4 @@ jobs:
|
|||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
uses: github/codeql-action/analyze@v1
|
||||
|
|
141
.github/workflows/release-please.yml
vendored
141
.github/workflows/release-please.yml
vendored
|
@ -1,141 +0,0 @@
|
|||
name: Run Release Please
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
|
||||
jobs:
|
||||
pre_check:
|
||||
name: Precheck for skipping redundant jobs
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
should_skip_lang: ${{ steps.skip_lang_check.outputs.should_skip }}
|
||||
should_skip_components: ${{ steps.skip_components_check.outputs.should_skip }}
|
||||
should_skip_website: ${{ steps.skip_website_check.outputs.should_skip }}
|
||||
should_skip_vscodeext: ${{ steps.skip_vscodeext_check.outputs.should_skip }}
|
||||
should_skip_cli: ${{ steps.skip_cli_check.outputs.should_skip }}
|
||||
steps:
|
||||
- id: skip_lang_check
|
||||
name: Check if the changes are about squiggle-lang src files
|
||||
uses: fkirc/skip-duplicate-actions@v5.2.0
|
||||
with:
|
||||
paths: '["packages/squiggle-lang/**"]'
|
||||
- id: skip_components_check
|
||||
name: Check if the changes are about components src files
|
||||
uses: fkirc/skip-duplicate-actions@v5.2.0
|
||||
with:
|
||||
paths: '["packages/components/**"]'
|
||||
- id: skip_website_check
|
||||
name: Check if the changes are about website src files
|
||||
uses: fkirc/skip-duplicate-actions@v5.2.0
|
||||
with:
|
||||
paths: '["packages/website/**"]'
|
||||
- id: skip_vscodeext_check
|
||||
name: Check if the changes are about vscode extension src files
|
||||
uses: fkirc/skip-duplicate-actions@v5.2.0
|
||||
with:
|
||||
paths: '["packages/vscode-ext/**"]'
|
||||
- id: skip_cli_check
|
||||
name: Check if the changes are about cli src files
|
||||
uses: fkirc/skip-duplicate-actions@v5.2.0
|
||||
with:
|
||||
paths: '["packages/cli/**"]'
|
||||
|
||||
relplz-lang:
|
||||
name: for squiggle-lang
|
||||
runs-on: ubuntu-latest
|
||||
needs: pre_check
|
||||
if: ${{ needs.pre_check.outputs.should_skip_lang != 'true' }}
|
||||
steps:
|
||||
- name: Release please (squiggle-lang)
|
||||
uses: google-github-actions/release-please-action@v3
|
||||
id: release
|
||||
with:
|
||||
token: ${{secrets.GITHUB_TOKEN}}
|
||||
command: manifest-pr
|
||||
path: packages/squiggle-lang
|
||||
# bump-patch-for-minor-pre-major: true
|
||||
skip-github-release: true
|
||||
- name: Publish- Checkout source
|
||||
uses: actions/checkout@v3
|
||||
# these if statements ensure that a publication only occurs when
|
||||
# a new release is created:
|
||||
if: ${{ steps.release.outputs.release_created }}
|
||||
- name: Publish- Install dependencies
|
||||
run: yarn
|
||||
if: ${{ steps.release.outputs.release_created }}
|
||||
- name: Publish
|
||||
run: cd packages/squiggle-lang && yarn publish
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
|
||||
if: ${{ steps.release.outputs.release_created }}
|
||||
|
||||
relplz-components:
|
||||
name: for components
|
||||
runs-on: ubuntu-latest
|
||||
needs: pre_check
|
||||
if: ${{ needs.pre_check.outputs.should_skip_components != 'true' }}
|
||||
steps:
|
||||
- name: Release please (components)
|
||||
uses: google-github-actions/release-please-action@v3
|
||||
with:
|
||||
token: ${{secrets.GITHUB_TOKEN}}
|
||||
command: manifest-pr
|
||||
path: packages/components
|
||||
# bump-patch-for-minor-pre-major: true
|
||||
skip-github-release: true
|
||||
- name: Publish- Checkout source
|
||||
uses: actions/checkout@v3
|
||||
# these if statements ensure that a publication only occurs when
|
||||
# a new release is created:
|
||||
if: ${{ steps.release.outputs.release_created }}
|
||||
- name: Publish- Install dependencies
|
||||
run: yarn
|
||||
if: ${{ steps.release.outputs.release_created }}
|
||||
- name: Publish
|
||||
run: cd packages/components && yarn publish
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
|
||||
relplz-website:
|
||||
name: for website
|
||||
runs-on: ubuntu-latest
|
||||
needs: pre_check
|
||||
if: ${{ needs.pre_check.outputs.should_skip_website != 'true' }}
|
||||
steps:
|
||||
- name: Release please (website)
|
||||
uses: google-github-actions/release-please-action@v3
|
||||
with:
|
||||
token: ${{secrets.GITHUB_TOKEN}}
|
||||
command: manifest-pr
|
||||
path: packages/website
|
||||
# bump-patch-for-minor-pre-major: true
|
||||
skip-github-release: true
|
||||
relplz-vscodeext:
|
||||
name: for vscode-ext
|
||||
runs-on: ubuntu-latest
|
||||
needs: pre_check
|
||||
if: ${{ needs.pre_check.outputs.should_skip_vscodeext != 'true' }}
|
||||
steps:
|
||||
- name: Release please (vscode-ext)
|
||||
uses: google-github-actions/release-please-action@v3
|
||||
with:
|
||||
token: ${{secrets.GITHUB_TOKEN}}
|
||||
command: manifest-pr
|
||||
path: packages/vscode-ext
|
||||
# bump-patch-for-minor-pre-major: true
|
||||
skip-github-release: true
|
||||
relplz-cl:
|
||||
name: for cli
|
||||
runs-on: ubuntu-latest
|
||||
needs: pre_check
|
||||
if: ${{ needs.pre_check.outputs.should_skip_cli != 'true' }}
|
||||
steps:
|
||||
- name: Release please (cli)
|
||||
uses: google-github-actions/release-please-action@v3
|
||||
with:
|
||||
token: ${{secrets.GITHUB_TOKEN}}
|
||||
command: manifest-pr
|
||||
path: packages/cli
|
||||
bump-patch-for-minor-pre-major: true
|
||||
skip-github-release: true
|
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -7,9 +7,3 @@ yarn-error.log
|
|||
**/.sync.ffs_db
|
||||
.direnv
|
||||
.log
|
||||
|
||||
.vscode
|
||||
todo.txt
|
||||
result
|
||||
shell.nix
|
||||
.turbo
|
||||
|
|
|
@ -1,16 +1,12 @@
|
|||
.direnv
|
||||
*.bs.js
|
||||
*.gen.tsx
|
||||
packages/*/dist
|
||||
packages/components/storybook-static
|
||||
node_modules
|
||||
packages/*/node_modules
|
||||
packages/website/.docusaurus
|
||||
packages/squiggle-lang/lib
|
||||
packages/squiggle-lang/.nyc_output/
|
||||
packages/squiggle-lang/coverage/
|
||||
packages/squiggle-lang/.cache/
|
||||
packages/website/build/
|
||||
packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_GeneratedParser.js
|
||||
packages/vscode-ext/media/vendor/
|
||||
packages/squiggle-lang/.nyc_output/
|
||||
packages/*/dist
|
||||
result
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
{
|
||||
"packages/cli": "0.0.3",
|
||||
"packages/components": "0.4.1",
|
||||
"packages/squiggle-lang": "0.4.1",
|
||||
"packages/vscode-ext": "0.4.1",
|
||||
"packages/website": "0.0.0"
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
See the [Changelog.mdx page](./packages/website/docs/Changelog.mdx) for the changelog.
|
|
@ -16,7 +16,7 @@ Squiggle is currently pre-alpha.
|
|||
|
||||
# Bug reports
|
||||
|
||||
Anyone (with a github account) can file an issue at any time. Please allow Slava, Sam, and Ozzie to triage, but otherwise just follow the suggestions in the issue templates.
|
||||
Anyone (with a github account) can file an issue at any time. Please allow Quinn, Sam, and Ozzie to triage, but otherwise just follow the suggestions in the issue templates.
|
||||
|
||||
# Project structure
|
||||
|
||||
|
@ -28,7 +28,7 @@ Squiggle is a **monorepo** with three **packages**.
|
|||
|
||||
# Deployment ops
|
||||
|
||||
We use Vercel, and it should only concern Slava, Sam, and Ozzie.
|
||||
We use netlify, and it should only concern Quinn, Sam, and Ozzie.
|
||||
|
||||
# Development environment, building, testing, dev server
|
||||
|
||||
|
@ -56,9 +56,9 @@ If you absolutely must, please prefix your commit message with `hotfix: `.
|
|||
|
||||
Please work against `develop` branch. **Do not** work against `master`.
|
||||
|
||||
- For rescript code: Slava and Ozzie are reviewers
|
||||
- For rescript code: Quinn and Ozzie are reviewers
|
||||
- For js or typescript code: Sam and Ozzie are reviewers
|
||||
- For ops code (i.e. yaml, package.json): Slava and Sam are reviewers
|
||||
- For ops code (i.e. yaml, package.json): Quinn and Sam are reviewers
|
||||
|
||||
Autopings are set up: if you are not autopinged, you are welcome to comment, but please do not use the formal review feature, send approvals, rejections, or merges.
|
||||
|
||||
|
|
51
README.md
51
README.md
|
@ -1,30 +1,19 @@
|
|||
# Squiggle
|
||||
|
||||
[![Packages check](https://github.com/quantified-uncertainty/squiggle/actions/workflows/ci.yml/badge.svg)](https://github.com/quantified-uncertainty/squiggle/actions/workflows/ci.yml)
|
||||
[![npm version - lang](https://badge.fury.io/js/@quri%2Fsquiggle-lang.svg)](https://www.npmjs.com/package/@quri/squiggle-lang)
|
||||
[![npm version - components](https://badge.fury.io/js/@quri%2Fsquiggle-components.svg)](https://www.npmjs.com/package/@quri/squiggle-components)
|
||||
[![npm version](https://badge.fury.io/js/@quri%2Fsquiggle-lang.svg)](https://www.npmjs.com/package/@quri/squiggle-lang)
|
||||
[![npm version](https://badge.fury.io/js/@quri%2Fsquiggle-components.svg)](https://www.npmjs.com/package/@quri/squiggle-components)
|
||||
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/quantified-uncertainty/squiggle/blob/develop/LICENSE)
|
||||
[![codecov](https://codecov.io/gh/quantified-uncertainty/squiggle/branch/develop/graph/badge.svg?token=QRLBL5CQ7C)](https://codecov.io/gh/quantified-uncertainty/squiggle)
|
||||
|
||||
_An estimation language_.
|
||||
|
||||
## Get started
|
||||
|
||||
- [Gallery](https://www.squiggle-language.com/docs/Discussions/Gallery)
|
||||
- [Squiggle playground](https://squiggle-language.com/playground)
|
||||
- [Language basics](https://www.squiggle-language.com/docs/Guides/Language)
|
||||
- [Squiggle functions source of truth](https://www.squiggle-language.com/docs/Guides/Functions)
|
||||
- [Known bugs](https://www.squiggle-language.com/docs/Discussions/Bugs)
|
||||
- [Original lesswrong sequence](https://www.lesswrong.com/s/rDe8QE5NvXcZYzgZ3)
|
||||
- [Author your squiggle models as Observable notebooks](https://observablehq.com/@hazelfire/squiggle)
|
||||
- [Use squiggle in VS Code](https://marketplace.visualstudio.com/items?itemName=QURI.vscode-squiggle)
|
||||
This is an experimental DSL/language for making probabilistic estimates. The full story can be found [here](https://www.lesswrong.com/s/rDe8QE5NvXcZYzgZ3).
|
||||
|
||||
## Our deployments
|
||||
|
||||
- **website/docs prod**: https://squiggle-language.com
|
||||
- **website/docs staging**: https://preview.squiggle-language.com
|
||||
- **components storybook prod**: https://components.squiggle-language.com
|
||||
- **components storybook staging**: https://preview-components.squiggle-language.com
|
||||
- **website/docs prod**: https://squiggle-language.com [![Netlify Status](https://api.netlify.com/api/v1/badges/2139af5c-671d-473d-a9f6-66c96077d8a1/deploy-status)](https://app.netlify.com/sites/squiggle-documentation/deploys)
|
||||
- **website/docs staging**: https://develop--squiggle-documentation.netlify.app/
|
||||
- **components storybook prod**: https://squiggle-components.netlify.app/ [![Netlify Status](https://api.netlify.com/api/v1/badges/b7f724aa-6b20-4d0e-bf86-3fcd1a3e9a70/deploy-status)](https://app.netlify.com/sites/squiggle-components/deploys)
|
||||
- **components storybook staging**: https://develop--squiggle-components.netlify.app/
|
||||
- **legacy (2020) playground**: https://playground.squiggle-language.com
|
||||
|
||||
## Packages
|
||||
|
@ -38,10 +27,10 @@ the packages can be found in `packages`.
|
|||
- `@quri/squiggle-components` in `packages/components` contains React components that
|
||||
can be passed squiggle strings as props, and return a presentation of the result
|
||||
of the calculation.
|
||||
- `packages/website` is the main descriptive website for squiggle,
|
||||
- `@quri/squiggle-website` in `packages/website` The main descriptive website for squiggle,
|
||||
it is hosted at `squiggle-language.com`.
|
||||
- `packages/vscode-ext` is the VS Code extension for writing estimation functions.
|
||||
- `packages/cli` is an experimental way of using imports in squiggle, which is also on [npm](https://www.npmjs.com/package/squiggle-cli-experimental).
|
||||
|
||||
The playground depends on the components library which then depends on the language. This means that if you wish to work on the components library, you will need to build (no need to bundle) the language, and as of this writing playground doesn't really work.
|
||||
|
||||
# Develop
|
||||
|
||||
|
@ -51,25 +40,7 @@ For any project in the repo, begin by running `yarn` in the top level
|
|||
yarn
|
||||
```
|
||||
|
||||
Then use `turbo` to build the specific packages or the entire monorepo:
|
||||
|
||||
```sh
|
||||
turbo run build
|
||||
```
|
||||
|
||||
Or:
|
||||
|
||||
```sh
|
||||
turbo run build --filter=@quri/squiggle-components
|
||||
```
|
||||
|
||||
You can also run specific npm scripts for the package you're working on. See `packages/*/README.md` for the details.
|
||||
|
||||
# NixOS users
|
||||
|
||||
This repository requires the use of bundled binaries from node_modules, which
|
||||
are not linked statically. The easiest way to get them working is to enable
|
||||
[nix-ld](https://github.com/Mic92/nix-ld).
|
||||
See `packages/*/README.md` to work with whatever project you're interested in.
|
||||
|
||||
# Contributing
|
||||
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
# The following code was provided by Nuño Sempere, it comes directly from the post https://www.lesswrong.com/s/rDe8QE5NvXcZYzgZ3/p/j8o6sgRerE3tqNWdj
|
||||
## Initial setup
|
||||
yearly_probability_max = 0.95
|
||||
yearly_probability_min = 0.66
|
||||
period_probability_function(epsilon, yearly_probability) = 1 - (1 - yearly_probability) ^ (1 / epsilon)
|
||||
probability_decayed(t, time_periods, period_probability) = 1 - (1 - period_probability) ^ (time_periods - t)
|
||||
|
||||
## Monthly decomposition
|
||||
months_in_a_year=12
|
||||
|
||||
monthly_probability_min = period_probability_function(months_in_a_year, yearly_probability_min)
|
||||
monthly_probability_max = period_probability_function(months_in_a_year, yearly_probability_max)
|
||||
|
||||
probability_decayed_monthly_min(t) = probability_decayed(t, months_in_a_year, monthly_probability_min)
|
||||
probability_decayed_monthly_max(t) = probability_decayed(t, months_in_a_year, monthly_probability_max)
|
||||
probability_decayed_monthly(t) = probability_decayed_monthly_min(t) to probability_decayed_monthly_max(t)
|
||||
|
||||
probability_decayed_monthly
|
||||
## probability_decayed_monthly(6)
|
||||
## mean(probability_decayed_monthly(6))
|
|
@ -1,38 +0,0 @@
|
|||
# This is a cost effectiveness analysis of givedirectly, originally done by givewell, and translated into Squiggle by Sam Nolan
|
||||
donation_size = 10000
|
||||
proportion_of_funding_available = beta(10, 2)
|
||||
total_funding_available = donation_size * proportion_of_funding_available
|
||||
household_size = 3.7 to 5.7
|
||||
size_of_transfer = 800 to 1200
|
||||
size_of_transfer_per_person = size_of_transfer / household_size
|
||||
|
||||
portion_invested = 0.3 to 0.5
|
||||
amount_invested = portion_invested * size_of_transfer_per_person
|
||||
amount_consumed = (1 - portion_invested) * size_of_transfer_per_person
|
||||
return_on_investment = 0.08 to 0.12
|
||||
increase_in_consumption_from_investments = return_on_investment * amount_invested
|
||||
baseline_consumption = 200 to 350
|
||||
log_increase_in_consumption = log(amount_consumed + baseline_consumption) + log(baseline_consumption)
|
||||
log_increase_in_consumption_from_investment = log(increase_in_consumption_from_investments + baseline_consumption) + log(baseline_consumption)
|
||||
investment_duration = 8 to 12
|
||||
discount_rate = beta(1.004, 20)
|
||||
|
||||
present_value_excluding_last_year = log_increase_in_consumption_from_investment * (1 - (1 + discount_rate) ^ (-investment_duration)) / (log(1 + discount_rate))
|
||||
|
||||
percent_of_investment_returned = 0.15 to 0.25
|
||||
|
||||
pv_consumption_last_year = (log(baseline_consumption + amount_invested * (return_on_investment + percent_of_investment_returned)) - log(baseline_consumption)) / (1 + discount_rate)^investment_duration
|
||||
|
||||
total_pv_of_cash_transfer = pv_consumption_last_year + present_value_excluding_last_year + log_increase_in_consumption
|
||||
|
||||
discount_negative_spoiler = 0.03 to 0.07
|
||||
|
||||
value_discounting_spoiler = discount_negative_spoiler * total_pv_of_cash_transfer
|
||||
|
||||
consumption_increase_per_household = value_discounting_spoiler * household_size
|
||||
|
||||
amount_of_transfers_made = total_funding_available / size_of_transfer
|
||||
|
||||
total_increase_in_ln_consumption = amount_of_transfers_made * consumption_increase_per_household
|
||||
|
||||
total_increase_in_ln_consumption
|
|
@ -1,3 +0,0 @@
|
|||
xY1 = 99
|
||||
aBa3 = xY1 * 2 + 1
|
||||
aBa3 * xY1 + aBa3
|
79
flake.lock
79
flake.lock
|
@ -1,79 +0,0 @@
|
|||
{
|
||||
"nodes": {
|
||||
"flake-utils": {
|
||||
"locked": {
|
||||
"lastModified": 1659877975,
|
||||
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils_2": {
|
||||
"locked": {
|
||||
"lastModified": 1659877975,
|
||||
"narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"gentype": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils_2",
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1661855866,
|
||||
"narHash": "sha256-+q0OOTyaq8eOn9BOWdPOCtSDOISW4A59v3mq3JOZyug=",
|
||||
"owner": "rescript-association",
|
||||
"repo": "genType",
|
||||
"rev": "6b5f164b4f6ced456019b7579a0ab7e0a86518ad",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "rescript-association",
|
||||
"repo": "genType",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1661617163,
|
||||
"narHash": "sha256-NN9Ky47j8ohgPhA9JZyfkYIbbAo6RJkGz+7h8/exVpE=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "0ba2543f8c855d7be8e90ef6c8dc89c1617e8a08",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"id": "nixpkgs",
|
||||
"ref": "nixos-22.05",
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"flake-utils": "flake-utils",
|
||||
"gentype": "gentype",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
99
flake.nix
99
flake.nix
|
@ -1,99 +0,0 @@
|
|||
{
|
||||
description = "Squiggle packages";
|
||||
|
||||
inputs = {
|
||||
nixpkgs.url = "nixpkgs/nixos-22.05";
|
||||
gentype = {
|
||||
url = "github:rescript-association/genType";
|
||||
inputs.nixpkgs.follows = "nixpkgs";
|
||||
};
|
||||
flake-utils.url = "github:numtide/flake-utils";
|
||||
};
|
||||
|
||||
outputs = { self, nixpkgs, gentype, flake-utils }:
|
||||
let
|
||||
version = builtins.substring 0 8 self.lastModifiedDate;
|
||||
overlays = [
|
||||
(final: prev: {
|
||||
# set the node version here
|
||||
nodejs = prev.nodejs-18_x;
|
||||
# The override is the only way to get it into mkYarnModules
|
||||
})
|
||||
];
|
||||
|
||||
commonFn = pkgs: {
|
||||
buildInputs = with pkgs; [ nodejs yarn ];
|
||||
prettier = with pkgs.nodePackages; [ prettier ];
|
||||
which = [ pkgs.which ];
|
||||
};
|
||||
gentypeOutputFn = pkgs: gentype.outputs.packages.${pkgs.system}.default;
|
||||
langFn = { pkgs, ... }:
|
||||
# Probably doesn't work on i686-linux
|
||||
import ./nix/squiggle-lang.nix {
|
||||
inherit pkgs commonFn gentypeOutputFn;
|
||||
};
|
||||
componentsFn = { pkgs, ... }:
|
||||
import ./nix/squiggle-components.nix { inherit pkgs commonFn langFn; };
|
||||
websiteFn = { pkgs, ... }:
|
||||
import ./nix/squiggle-website.nix {
|
||||
inherit pkgs commonFn langFn componentsFn;
|
||||
};
|
||||
vscodeextFn = { pkgs, ... }:
|
||||
import ./nix/squiggle-vscode.nix {
|
||||
inherit pkgs commonFn langFn componentsFn;
|
||||
};
|
||||
cliFn = { pkgs, ... }:
|
||||
import ./nix/squiggle-cli.nix {
|
||||
inherit pkgs commonFn;
|
||||
};
|
||||
|
||||
# local machines
|
||||
localFlakeOutputs = { pkgs, ... }:
|
||||
let
|
||||
lang = langFn pkgs;
|
||||
components = componentsFn pkgs;
|
||||
website = websiteFn pkgs;
|
||||
vscodeext = vscodeextFn pkgs;
|
||||
cli = cliFn pkgs;
|
||||
in {
|
||||
# validating
|
||||
checks = flake-utils.lib.flattenTree {
|
||||
lang-lint = lang.lint;
|
||||
lang-test = lang.test;
|
||||
components-lint = components.lint;
|
||||
docusaurus-lint = website.lint;
|
||||
cli-lint = cli.lint;
|
||||
};
|
||||
# building
|
||||
packages = flake-utils.lib.flattenTree {
|
||||
default = components.build;
|
||||
lang = lang.build;
|
||||
lang-bundle = lang.bundle;
|
||||
lang-test = lang.test;
|
||||
components = components.build;
|
||||
components-bundle = components.bundle;
|
||||
|
||||
# Lint
|
||||
lang-lint = lang.lint;
|
||||
components-lint = components.lint;
|
||||
docusaurus-lint = website.lint;
|
||||
vscode-lint = vscodeext.lint;
|
||||
cli-lint = cli.lint;
|
||||
};
|
||||
|
||||
# developing
|
||||
devShells = let shellNix = import ./nix/shell.nix { inherit pkgs; };
|
||||
in flake-utils.lib.flattenTree {
|
||||
default = shellNix.all;
|
||||
js = shellNix.just-js;
|
||||
};
|
||||
};
|
||||
in flake-utils.lib.eachDefaultSystem (system:
|
||||
let
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
overlays = overlays;
|
||||
};
|
||||
|
||||
in localFlakeOutputs pkgs);
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
Visit `quantified-uncertainty.cachix.org` for information about how to add our binary cache to your local dev environment.
|
|
@ -1,25 +0,0 @@
|
|||
{ pkgs }:
|
||||
with pkgs;
|
||||
let
|
||||
js = [ yarn nodejs nodePackages.ts-node ];
|
||||
rust = [
|
||||
wasm-pack
|
||||
cargo
|
||||
rustup
|
||||
pkg-config
|
||||
libressl
|
||||
rustfmt
|
||||
wasmtime
|
||||
binaryen
|
||||
wasm-bindgen-cli
|
||||
];
|
||||
in {
|
||||
all = mkShell {
|
||||
name = "squiggle_yarn-wasm-devshell";
|
||||
buildInputs = builtins.concatLists [ js rust [ nixfmt ] ];
|
||||
};
|
||||
just-js = mkShell {
|
||||
name = "squiggle_yarn-devshell";
|
||||
buildInputs = js ++ [ nixfmt ];
|
||||
};
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
{ pkgs, commonFn }:
|
||||
|
||||
rec {
|
||||
common = commonFn pkgs;
|
||||
|
||||
lint = pkgs.stdenv.mkDerivation {
|
||||
name = "squiggle-cli-lint";
|
||||
buildInputs = common.buildInputs ++ common.prettier;
|
||||
src = ../packages/cli;
|
||||
buildPhase = "prettier --check .";
|
||||
installPhase = "mkdir -p $out";
|
||||
};
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
{ pkgs, commonFn, langFn }:
|
||||
|
||||
rec {
|
||||
common = commonFn pkgs;
|
||||
lang = langFn pkgs;
|
||||
componentsPackageJson = let
|
||||
raw = pkgs.lib.importJSON ../packages/components/package.json;
|
||||
modified =
|
||||
pkgs.lib.recursiveUpdate raw { dependencies.react-dom = "^18.2.0"; };
|
||||
packageJsonString = builtins.toJSON modified;
|
||||
in pkgs.writeText "packages/components/patched-package.json"
|
||||
packageJsonString;
|
||||
yarn-source = pkgs.mkYarnPackage {
|
||||
name = "squiggle-components_yarnsource";
|
||||
buildInputs = common.buildInputs;
|
||||
src = ../packages/components;
|
||||
packageJSON = componentsPackageJson;
|
||||
yarnLock = ../yarn.lock;
|
||||
packageResolutions."@quri/squiggle-lang" = lang.build;
|
||||
};
|
||||
lint = pkgs.stdenv.mkDerivation {
|
||||
name = "squiggle-components-lint";
|
||||
src = ../packages/components;
|
||||
buildInputs = common.buildInputs ++ common.prettier;
|
||||
buildPhase = "yarn lint";
|
||||
installPhase = "mkdir -p $out";
|
||||
};
|
||||
build = pkgs.stdenv.mkDerivation {
|
||||
name = "squiggle-components-build";
|
||||
src = yarn-source + "/libexec/@quri/squiggle-components";
|
||||
buildInputs = common.buildInputs;
|
||||
buildPhase = ''
|
||||
cp -r node_modules/@quri/squiggle-lang deps/@quri
|
||||
pushd deps/@quri/squiggle-components
|
||||
|
||||
yarn --offline build:cjs
|
||||
yarn --offline build:css
|
||||
popd
|
||||
'';
|
||||
installPhase = ''
|
||||
mkdir -p $out
|
||||
|
||||
# annoying hack because permissions on transitive dependencies later on
|
||||
mv deps/@quri/squiggle-components/node_modules deps/@quri/squiggle-components/NODE_MODULES
|
||||
mv node_modules deps/@quri/squiggle-components
|
||||
|
||||
# patching .gitignore so flake keeps build artefacts
|
||||
sed -i /dist/d deps/@quri/squiggle-components/.gitignore
|
||||
cp -r deps/@quri/squiggle-components/. $out
|
||||
'';
|
||||
};
|
||||
bundle = pkgs.stdenv.mkDerivation {
|
||||
name = "squiggle-components-bundle";
|
||||
src = yarn-source + "/libexec/@quri/squiggle-components";
|
||||
buildInputs = common.buildInputs;
|
||||
buildPhase = ''
|
||||
cp -r node_modules/@quri/squiggle-lang deps/@quri
|
||||
pushd deps/@quri/squiggle-components
|
||||
|
||||
yarn --offline bundle
|
||||
popd
|
||||
'';
|
||||
installPhase = ''
|
||||
mkdir -p $out
|
||||
|
||||
# annoying hack because permissions on transitive dependencies later on
|
||||
mv deps/@quri/squiggle-components/node_modules deps/@quri/squiggle-components/NODE_MODULES
|
||||
mv node_modules deps/@quri/squiggle-components
|
||||
|
||||
# patching .gitignore so flake keeps build artefacts
|
||||
sed -i /dist/d deps/@quri/squiggle-components/.gitignore
|
||||
cp -r deps/@quri/squiggle-components/. $out
|
||||
'';
|
||||
};
|
||||
}
|
|
@ -1,116 +0,0 @@
|
|||
{ pkgs, commonFn, gentypeOutputFn }:
|
||||
|
||||
rec {
|
||||
common = commonFn pkgs;
|
||||
langPackageJson = let
|
||||
raw = pkgs.lib.importJSON ../packages/squiggle-lang/package.json;
|
||||
modified = pkgs.lib.recursiveUpdate raw {
|
||||
devDependencies."@types/lodash" = "^4.14.167";
|
||||
};
|
||||
packageJsonString = builtins.toJSON modified;
|
||||
in pkgs.writeText "packages/squiggle-lang/patched-package.json"
|
||||
packageJsonString;
|
||||
yarn-source = pkgs.mkYarnPackage {
|
||||
name = "squiggle-lang_yarnsource";
|
||||
src = ../packages/squiggle-lang;
|
||||
packageJSON = langPackageJson;
|
||||
yarnLock = ../yarn.lock;
|
||||
pkgConfig = {
|
||||
rescript = {
|
||||
buildInputs = common.which
|
||||
++ (if pkgs.system != "i686-linux" then [ pkgs.gcc_multi ] else [ ]);
|
||||
postInstall = ''
|
||||
echo "PATCHELF'ING RESCRIPT EXECUTABLES (INCL NINJA)"
|
||||
# Patching interpreter for linux/*.exe's
|
||||
THE_LD=$(patchelf --print-interpreter $(which mkdir))
|
||||
patchelf --set-interpreter $THE_LD linux/*.exe && echo "- patched interpreter for linux/*.exe's"
|
||||
|
||||
# Replacing needed shared library for linux/ninja.exe
|
||||
THE_SO=$(find /nix/store/*/lib64 -name libstdc++.so.6 | head -n 1)
|
||||
patchelf --replace-needed libstdc++.so.6 $THE_SO linux/ninja.exe && echo "- replaced needed for linux/ninja.exe"
|
||||
'';
|
||||
};
|
||||
gentype = {
|
||||
postInstall = ''
|
||||
mv gentype.exe ELFLESS-gentype.exe
|
||||
cp ${gentypeOutputFn pkgs}/src/GenType.exe gentype.exe
|
||||
'';
|
||||
};
|
||||
};
|
||||
};
|
||||
lint = pkgs.stdenv.mkDerivation {
|
||||
name = "squiggle-lang-lint";
|
||||
src = yarn-source + "/libexec/@quri/squiggle-lang/deps/@quri/squiggle-lang";
|
||||
buildInputs = common.buildInputs ++ common.prettier;
|
||||
buildPhase = ''
|
||||
yarn lint:prettier
|
||||
yarn lint:rescript
|
||||
'';
|
||||
installPhase = "mkdir -p $out";
|
||||
};
|
||||
build = pkgs.stdenv.mkDerivation {
|
||||
name = "squiggle-lang-build";
|
||||
# `peggy` is in the `node_modules` that's adjacent to `deps`.
|
||||
src = yarn-source + "/libexec/@quri/squiggle-lang";
|
||||
buildInputs = common.buildInputs;
|
||||
buildPhase = ''
|
||||
# so that the path to ppx doesn't need to be patched.
|
||||
mv node_modules deps
|
||||
|
||||
pushd deps/@quri/squiggle-lang
|
||||
yarn --offline build:peggy
|
||||
yarn --offline build:rescript
|
||||
yarn --offline build:typescript
|
||||
|
||||
# custom gitignore so that the flake keeps build artefacts
|
||||
mv .gitignore GITIGNORE
|
||||
sed -i /Reducer_Peggy_GeneratedParser.js/d GITIGNORE
|
||||
sed -i /ReducerProject_IncludeParser.js/d GITIGNORE
|
||||
sed -i /\*.bs.js/d GITIGNORE
|
||||
sed -i /\*.gen.ts/d GITIGNORE
|
||||
sed -i /\*.gen.tsx/d GITIGNORE
|
||||
sed -i /\*.gen.js/d GITIGNORE
|
||||
sed -i /helpers.js/d GITIGNORE
|
||||
|
||||
popd
|
||||
'';
|
||||
installPhase = ''
|
||||
mkdir -p $out
|
||||
# mkdir -p $out/node_modules
|
||||
mv deps/@quri/squiggle-lang/GITIGNORE deps/@quri/squiggle-lang/.gitignore
|
||||
|
||||
# annoying hack because permissions on transitive dependencies later on
|
||||
mv deps/@quri/squiggle-lang/node_modules deps/@quri/squiggle-lang/NODE_MODULES
|
||||
mv deps/node_modules deps/@quri/squiggle-lang
|
||||
|
||||
# the proper install phase
|
||||
cp -r deps/@quri/squiggle-lang/. $out
|
||||
'';
|
||||
};
|
||||
test = pkgs.stdenv.mkDerivation {
|
||||
name = "squiggle-lang-test";
|
||||
src = build;
|
||||
buildInputs = common.buildInputs;
|
||||
buildPhase = ''
|
||||
yarn --offline test
|
||||
'';
|
||||
installPhase = ''
|
||||
mkdir -p $out
|
||||
cp -r . $out
|
||||
'';
|
||||
};
|
||||
bundle = pkgs.stdenv.mkDerivation {
|
||||
name = "squiggle-lang-bundle";
|
||||
src = test;
|
||||
buildInputs = common.buildInputs;
|
||||
buildPhase = ''
|
||||
yarn --offline bundle
|
||||
'';
|
||||
installPhase = ''
|
||||
mkdir -p $out
|
||||
cp -r dist $out
|
||||
cp *.json $out/dist
|
||||
'';
|
||||
};
|
||||
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
{ pkgs, commonFn, langFn, componentsFn }:
|
||||
|
||||
rec {
|
||||
common = commonFn pkgs;
|
||||
lang = langFn pkgs;
|
||||
components = componentsFn pkgs;
|
||||
|
||||
yarn-source = pkgs.mkYarnPackage {
|
||||
name = "squiggle-vscodeext_yarnsource";
|
||||
src = ../packages/vscode-ext;
|
||||
packageJson = ../packages/vscode-ext/package.json;
|
||||
yarnLock = ../yarn.lock;
|
||||
packageResolutions."@quri/squiggle-lang" = lang.build;
|
||||
packageResolutions."@quri/squiggle-components" = components.build;
|
||||
};
|
||||
lint = pkgs.stdenv.mkDerivation {
|
||||
name = "squiggle-vscode-lint";
|
||||
buildInputs = common.buildInputs ++ common.prettier;
|
||||
src =
|
||||
../packages/vscode-ext; # yarn-source + "/libexec/vscode-squiggle/deps/vscode-squiggle";
|
||||
buildPhase = "prettier --check .";
|
||||
installPhase = "mkdir -p $out";
|
||||
};
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
{ pkgs, commonFn, langFn, componentsFn }:
|
||||
|
||||
rec {
|
||||
common = commonFn pkgs;
|
||||
lang = langFn pkgs;
|
||||
components = componentsFn pkgs;
|
||||
websitePackageJson = let
|
||||
raw = pkgs.lib.importJSON ../packages/website/package.json;
|
||||
modified = pkgs.lib.recursiveUpdate raw {
|
||||
dependencies.postcss-import = "^14.1.0";
|
||||
dependencies.tailwindcss = "^3.1.8";
|
||||
};
|
||||
packageJsonString = builtins.toJSON modified;
|
||||
in pkgs.writeText "packages/website/patched-package.json" packageJsonString;
|
||||
yarn-source = pkgs.mkYarnPackage {
|
||||
name = "squiggle-website_yarnsource";
|
||||
src = ../packages/website;
|
||||
packageJSON = websitePackageJson;
|
||||
yarnLock = ../yarn.lock;
|
||||
packageResolutions."@quri/squiggle-lang" = lang.build;
|
||||
packageResolutions."@quri/squiggle-components" = components.build;
|
||||
};
|
||||
lint = pkgs.stdenv.mkDerivation {
|
||||
name = "squiggle-website-lint";
|
||||
buildInputs = common.buildInputs ++ common.prettier;
|
||||
src = ../packages/website;
|
||||
buildPhase = "yarn lint";
|
||||
installPhase = "mkdir -p $out";
|
||||
};
|
||||
}
|
18
nixos.sh
Executable file
18
nixos.sh
Executable file
|
@ -0,0 +1,18 @@
|
|||
#!/usr/bin/env bash
|
||||
# This script is only relevant if you're rolling nixos.
|
||||
|
||||
# Esy (a bisect_ppx dependency/build tool) is borked on nixos without using an FHS shell. https://github.com/esy/esy/issues/858
|
||||
# We need to patchelf rescript executables. https://github.com/NixOS/nixpkgs/issues/107375
|
||||
set -x
|
||||
|
||||
fhsShellName="squiggle-development"
|
||||
fhsShellDotNix="{pkgs ? import <nixpkgs> {} }: (pkgs.buildFHSUserEnv { name = \"${fhsShellName}\"; targetPkgs = pkgs: [pkgs.yarn]; runScript = \"yarn\"; }).env"
|
||||
nix-shell - <<<"$fhsShellDotNix"
|
||||
|
||||
theLd=$(patchelf --print-interpreter $(which mkdir))
|
||||
patchelf --set-interpreter $theLd ./node_modules/gentype/gentype.exe
|
||||
patchelf --set-interpreter $theLd ./node_modules/rescript/linux/*.exe
|
||||
patchelf --set-interpreter $theLd ./node_modules/bisect_ppx/ppx
|
||||
patchelf --set-interpreter $theLd ./node_moduels/bisect_ppx/bisect-ppx-report
|
||||
theSo=$(find /nix/store/*$fhsShellName*/lib64 -name libstdc++.so.6 | grep $fhsShellName | head -n 1)
|
||||
patchelf --replace-needed libstdc++.so.6 $theSo ./node_modules/rescript/linux/ninja.exe
|
|
@ -2,11 +2,12 @@
|
|||
"private": true,
|
||||
"name": "squiggle",
|
||||
"scripts": {
|
||||
"nodeclean": "rm -r node_modules && rm -r packages/*/node_modules"
|
||||
"nodeclean": "rm -r node_modules && rm -r packages/*/node_modules",
|
||||
"format:all": "prettier --write . && cd packages/squiggle-lang && yarn format",
|
||||
"lint:all": "prettier --check . && cd packages/squiggle-lang && yarn lint:rescript"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier": "^2.7.1",
|
||||
"turbo": "^1.5.5"
|
||||
"prettier": "^2.6.2"
|
||||
},
|
||||
"workspaces": [
|
||||
"packages/*"
|
||||
|
|
4
packages/cli/.gitignore
vendored
4
packages/cli/.gitignore
vendored
|
@ -1,4 +0,0 @@
|
|||
## Artifacts
|
||||
*.swp
|
||||
/node_modules/
|
||||
yarn-error.log
|
|
@ -1,49 +0,0 @@
|
|||
## Squiggle CLI
|
||||
|
||||
This package can be used to incorporate a very simple `import` system into Squiggle.
|
||||
|
||||
To use, write special files with a `.squiggleU` file type. In these files, you can write lines like,
|
||||
|
||||
```
|
||||
@import(models/gdp_over_time.squiggle, gdpOverTime)
|
||||
gdpOverTime(2.5)
|
||||
```
|
||||
|
||||
The imports will be replaced with the contents of the file in `models/gdp_over_time.squiggle` upon compilation. The `.squiggleU` file will be converted into a `.squiggle` file with the `import` statement having this replacement.
|
||||
|
||||
## Running
|
||||
|
||||
### `npx squiggle-cli-experimental compile`
|
||||
|
||||
Runs compilation in the current directory and all of its subdirectories.
|
||||
|
||||
### `npx squiggle-cli-experimental watch`
|
||||
|
||||
Watches `.squiggleU` files in the current directory (and subdirectories) and rebuilds them when they are saved. Note that this will _not_ rebuild files when their dependencies are changed, just when they are changed directly.
|
||||
|
||||
## Further instructions
|
||||
|
||||
The above requires having node, npm and npx. To install the first two, see [here](https://nodejs.org/en/), to install npx, run:
|
||||
|
||||
```
|
||||
npm install -g npx
|
||||
```
|
||||
|
||||
Alternatively, you can run the following without the need for npx:
|
||||
|
||||
```
|
||||
npm install squiggle-cli-experimental
|
||||
node node_modules/squiggle-cli-experimental/index.js compile
|
||||
```
|
||||
|
||||
or you can add a script to your `package.json`, like:
|
||||
|
||||
```
|
||||
...
|
||||
scripts: {
|
||||
"compile": "squiggle-cli-experimental compile"
|
||||
}
|
||||
...
|
||||
```
|
||||
|
||||
This can be run with `npm run compile`. `npm` knows how to reach into the node_modules directly, so it's not necessary to specify that.
|
|
@ -1,96 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import indentString from "indent-string";
|
||||
import chokidar from "chokidar";
|
||||
import chalk from "chalk";
|
||||
import { Command } from "commander";
|
||||
import glob from "glob";
|
||||
|
||||
const processFile = (fileName, seen = []) => {
|
||||
const normalizedFileName = path.resolve(fileName);
|
||||
if (seen.includes(normalizedFileName)) {
|
||||
throw new Error(`Recursive dependency for file ${fileName}`);
|
||||
}
|
||||
|
||||
const fileContents = fs.readFileSync(fileName, "utf-8");
|
||||
if (!fileName.endsWith(".squiggleU")) {
|
||||
return fileContents;
|
||||
}
|
||||
|
||||
const regex = /\@import\(\s*([^)]+?)\s*\)/g;
|
||||
const matches = Array.from(fileContents.matchAll(regex)).map((r) =>
|
||||
r[1].split(/\s*,\s*/)
|
||||
);
|
||||
const newContent = fileContents.replaceAll(regex, "");
|
||||
const appendings = [];
|
||||
|
||||
matches.forEach((r) => {
|
||||
const importFileName = r[0];
|
||||
const rename = r[1];
|
||||
const item = fs.statSync(importFileName);
|
||||
if (item.isFile()) {
|
||||
const data = processFile(importFileName, [...seen, normalizedFileName]);
|
||||
if (data) {
|
||||
const importString = `${rename} = {\n${indentString(data, 2)}\n}\n`;
|
||||
appendings.push(importString);
|
||||
}
|
||||
} else {
|
||||
console.log(
|
||||
chalk.red(`Import Error`) +
|
||||
`: ` +
|
||||
chalk.cyan(importFileName) +
|
||||
` not found in file ` +
|
||||
chalk.cyan(fileName) +
|
||||
`. Make sure the @import file names all exist in this repo.`
|
||||
);
|
||||
}
|
||||
});
|
||||
const imports = appendings.join("\n");
|
||||
|
||||
const newerContent = imports.concat(newContent);
|
||||
return newerContent;
|
||||
};
|
||||
|
||||
const run = (fileName) => {
|
||||
const content = processFile(fileName);
|
||||
const parsedPath = path.parse(path.resolve(fileName));
|
||||
const newFilename = `${parsedPath.dir}/${parsedPath.name}.squiggle`;
|
||||
fs.writeFileSync(newFilename, content);
|
||||
console.log(chalk.cyan(`Updated ${fileName} -> ${newFilename}`));
|
||||
};
|
||||
|
||||
const compile = () => {
|
||||
glob("**/*.squiggleU", (_err, files) => {
|
||||
files.forEach(run);
|
||||
});
|
||||
};
|
||||
|
||||
const watch = () => {
|
||||
chokidar
|
||||
.watch("**.squiggleU")
|
||||
.on("ready", () => console.log(chalk.green("Ready!")))
|
||||
.on("change", (event, _) => {
|
||||
run(event);
|
||||
});
|
||||
};
|
||||
|
||||
const program = new Command();
|
||||
|
||||
program
|
||||
.name("squiggle-utils")
|
||||
.description("CLI to transform squiggle files with @imports")
|
||||
.version("0.0.1");
|
||||
|
||||
program
|
||||
.command("watch")
|
||||
.description("watch files and compile on the fly")
|
||||
.action(watch);
|
||||
|
||||
program
|
||||
.command("compile")
|
||||
.description("compile all .squiggleU files into .squiggle files")
|
||||
.action(compile);
|
||||
|
||||
program.parse();
|
|
@ -1,23 +0,0 @@
|
|||
{
|
||||
"name": "squiggle-cli-experimental",
|
||||
"version": "0.0.3",
|
||||
"main": "index.js",
|
||||
"homepage": "https://squiggle-language.com",
|
||||
"author": "Quantified Uncertainty Research Institute",
|
||||
"bin": "index.js",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"start": "node .",
|
||||
"lint": "prettier --check .",
|
||||
"format": "prettier --write ."
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"chalk": "^5.1.0",
|
||||
"chokidar": "^3.5.3",
|
||||
"commander": "^9.4.1",
|
||||
"fs": "^0.0.1-security",
|
||||
"glob": "^8.0.3",
|
||||
"indent-string": "^5.0.0"
|
||||
}
|
||||
}
|
|
@ -1,4 +1,2 @@
|
|||
dist/
|
||||
storybook-static
|
||||
src/styles/base.css
|
||||
src/styles/forms.css
|
||||
|
|
|
@ -1,15 +1,3 @@
|
|||
import "../src/styles/main.css";
|
||||
import "!style-loader!css-loader!postcss-loader!../src/styles/main.css";
|
||||
import { SquiggleContainer } from "../src/components/SquiggleContainer";
|
||||
|
||||
export const decorators = [
|
||||
(Story) => (
|
||||
<SquiggleContainer>
|
||||
<Story />
|
||||
</SquiggleContainer>
|
||||
),
|
||||
];
|
||||
|
||||
export const parameters = {
|
||||
actions: { argTypesRegex: "^on[A-Z].*" },
|
||||
controls: {
|
||||
|
|
|
@ -1,67 +1,8 @@
|
|||
[![npm version](https://badge.fury.io/js/@quri%2Fsquiggle-components.svg)](https://www.npmjs.com/package/@quri/squiggle-components)
|
||||
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/quantified-uncertainty/squiggle/blob/develop/LICENSE)
|
||||
# Squiggle Components
|
||||
|
||||
# Squiggle components
|
||||
This package contains all the components for squiggle. These can be used either as a library or hosted as a [storybook](https://storybook.js.org/).
|
||||
|
||||
This package contains the react components for squiggle. These can be used either as a library or hosted as a [storybook](https://storybook.js.org/).
|
||||
|
||||
The `@quri/squiggle-components` package offers several components and utilities for people who want to embed Squiggle components into websites.
|
||||
|
||||
# Usage in a `react` project
|
||||
|
||||
For example, in a fresh `create-react-app` project
|
||||
|
||||
```sh
|
||||
yarn add @quri/squiggle-components
|
||||
```
|
||||
|
||||
Add to `App.js`:
|
||||
|
||||
```jsx
|
||||
import { SquiggleEditor } from "@quri/squiggle-components";
|
||||
<SquiggleEditor
|
||||
defaultCode="x = beta($alpha, 10); x + $shift"
|
||||
jsImports={{ alpha: 3, shift: 20 }}
|
||||
/>;
|
||||
```
|
||||
|
||||
# Usage in a Nextjs project
|
||||
|
||||
For now, `squiggle-components` requires the `window` property, so using the package in nextjs requires dynamic loading:
|
||||
|
||||
```
|
||||
|
||||
import React from "react";
|
||||
import { SquiggleChart } from "@quri/squiggle-components";
|
||||
|
||||
import dynamic from "next/dynamic";
|
||||
|
||||
const SquiggleChart = dynamic(
|
||||
() => import("@quri/squiggle-components").then((mod) => mod.SquiggleChart),
|
||||
{
|
||||
loading: () => <p>Loading...</p>,
|
||||
ssr: false,
|
||||
}
|
||||
);
|
||||
|
||||
export function DynamicSquiggleChart({ squiggleString }) {
|
||||
if (squiggleString == "") {
|
||||
return null;
|
||||
} else {
|
||||
return (
|
||||
<SquiggleChart
|
||||
defaultCode={squiggleString}
|
||||
width={445}
|
||||
height={200}
|
||||
showSummary={true}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
# Build storybook for development
|
||||
# Build for development
|
||||
|
||||
We assume that you had run `yarn` at monorepo level, installing dependencies.
|
||||
|
||||
|
@ -79,3 +20,10 @@ Run a development server
|
|||
```sh
|
||||
yarn start
|
||||
```
|
||||
|
||||
And build artefacts for production,
|
||||
|
||||
```sh
|
||||
yarn bundle # builds components library
|
||||
yarn build # builds storybook app
|
||||
```
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
/** @type {import('ts-jest').JestConfigWithTsJest} */
|
||||
module.exports = {
|
||||
preset: "ts-jest",
|
||||
setupFilesAfterEnv: ["<rootDir>/test/setup.js"],
|
||||
testEnvironment: "jsdom",
|
||||
};
|
8
packages/components/netlify.toml
Normal file
8
packages/components/netlify.toml
Normal file
|
@ -0,0 +1,8 @@
|
|||
[build]
|
||||
base = "packages/components/"
|
||||
command = "cd ../squiggle-lang && yarn build && cd ../components && yarn build"
|
||||
publish = "storybook-static/"
|
||||
ignore = "node -e 'process.exitCode = process.env.BRANCH.includes(\"dependabot\") ? 0 : 1' && git diff --quiet $CACHED_COMMIT_REF $COMMIT_REF . ../squiggle-lang"
|
||||
|
||||
[build.environment]
|
||||
NETLIFY_USE_YARN = "true"
|
|
@ -1,92 +1,41 @@
|
|||
{
|
||||
"name": "@quri/squiggle-components",
|
||||
"version": "0.5.0",
|
||||
"license": "MIT",
|
||||
"version": "0.1.8",
|
||||
"dependencies": {
|
||||
"@floating-ui/react-dom": "^1.0.0",
|
||||
"@floating-ui/react-dom-interactions": "^0.10.1",
|
||||
"@headlessui/react": "^1.7.3",
|
||||
"@heroicons/react": "^1.0.6",
|
||||
"@hookform/resolvers": "^2.9.8",
|
||||
"@quri/squiggle-lang": "^0.5.0",
|
||||
"@quri/squiggle-lang": "0.2.2",
|
||||
"@react-hook/size": "^2.1.2",
|
||||
"@types/uuid": "^8.3.4",
|
||||
"clsx": "^1.2.1",
|
||||
"framer-motion": "^7.5.3",
|
||||
"lodash": "^4.17.21",
|
||||
"react": "^18.1.0",
|
||||
"react-ace": "^10.1.0",
|
||||
"react-hook-form": "^7.37.0",
|
||||
"react-use": "^17.4.0",
|
||||
"react-vega": "^7.6.0",
|
||||
"uuid": "^9.0.0",
|
||||
"vega": "^5.22.1",
|
||||
"vega-embed": "^6.21.0",
|
||||
"vega-lite": "^5.5.0",
|
||||
"vscode-uri": "^3.0.6",
|
||||
"yup": "^0.32.11"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/plugin-proposal-private-property-in-object": "^7.18.6",
|
||||
"@storybook/addon-actions": "^6.5.12",
|
||||
"@storybook/addon-essentials": "^6.5.12",
|
||||
"@storybook/addon-links": "^6.5.12",
|
||||
"@storybook/builder-webpack5": "^6.5.12",
|
||||
"@storybook/manager-webpack5": "^6.5.12",
|
||||
"@storybook/node-logger": "^6.5.9",
|
||||
"@storybook/preset-create-react-app": "^4.1.2",
|
||||
"@storybook/react": "^6.5.12",
|
||||
"@testing-library/jest-dom": "^5.16.5",
|
||||
"@testing-library/react": "^13.4.0",
|
||||
"@testing-library/user-event": "^14.4.3",
|
||||
"@types/jest": "^27.5.0",
|
||||
"@types/lodash": "^4.14.186",
|
||||
"@types/node": "^18.8.3",
|
||||
"@types/react": "^18.0.21",
|
||||
"@types/styled-components": "^5.1.26",
|
||||
"@types/uuid": "^8.3.4",
|
||||
"@types/webpack": "^5.28.0",
|
||||
"canvas": "^2.10.1",
|
||||
"@testing-library/jest-dom": "^5.16.4",
|
||||
"@testing-library/react": "^13.1.1",
|
||||
"@testing-library/user-event": "^14.1.1",
|
||||
"@types/jest": "^27.4.0",
|
||||
"@types/lodash": "^4.14.182",
|
||||
"@types/node": "^17.0.25",
|
||||
"@types/react": "^18.0.3",
|
||||
"@types/react-dom": "^18.0.2",
|
||||
"antd": "^4.19.3",
|
||||
"cross-env": "^7.0.3",
|
||||
"jest": "^29.0.3",
|
||||
"jest-environment-jsdom": "^29.1.2",
|
||||
"jsdom": "^20.0.1",
|
||||
"mini-css-extract-plugin": "^2.6.1",
|
||||
"postcss-cli": "^10.0.0",
|
||||
"postcss-import": "^15.0.0",
|
||||
"postcss-loader": "^7.0.1",
|
||||
"postcss-nesting": "^10.2.0",
|
||||
"react": "^18.1.0",
|
||||
"react-scripts": "^5.0.1",
|
||||
"style-loader": "^3.3.1",
|
||||
"tailwindcss": "^3.1.8",
|
||||
"ts-jest": "^29.0.3",
|
||||
"ts-loader": "^9.4.1",
|
||||
"tsconfig-paths-webpack-plugin": "^4.0.0",
|
||||
"typescript": "^4.8.4",
|
||||
"web-vitals": "^3.0.3",
|
||||
"webpack": "^5.74.0",
|
||||
"webpack-cli": "^4.10.0",
|
||||
"webpack-dev-server": "^4.11.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.8.0 || ^17 || ^18",
|
||||
"react-dom": "^16.8.0 || ^17 || ^18"
|
||||
"lodash": "^4.17.21",
|
||||
"react": "^18.0.0",
|
||||
"react-ace": "10.0.0",
|
||||
"react-dom": "^18.0.0",
|
||||
"react-scripts": "5.0.1",
|
||||
"react-vega": "^7.5.0",
|
||||
"styled-components": "^5.3.5",
|
||||
"tsconfig-paths-webpack-plugin": "^3.5.2",
|
||||
"typescript": "^4.6.3",
|
||||
"vega": "^5.22.1",
|
||||
"vega-embed": "^6.20.6",
|
||||
"vega-lite": "^5.2.0",
|
||||
"web-vitals": "^2.1.4",
|
||||
"webpack-cli": "^4.9.2"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "cross-env REACT_APP_FAST_REFRESH=false && start-storybook -p 6006 -s public",
|
||||
"build:cjs": "rm -rf dist/src && rm -f dist/tsconfig.tsbuildinfo && tsc -b",
|
||||
"build:css": "postcss ./src/styles/main.css -o ./dist/main.css",
|
||||
"build:storybook": "build-storybook -s public",
|
||||
"build": "yarn run build:cjs && yarn run build:css && yarn run build:storybook",
|
||||
"build": "tsc -b && build-storybook -s public",
|
||||
"bundle": "webpack",
|
||||
"all": "yarn bundle && yarn build",
|
||||
"lint": "prettier --check .",
|
||||
"format": "prettier --write .",
|
||||
"prepack": "yarn run build:cjs && yarn run bundle",
|
||||
"test": "jest",
|
||||
"test:debug": "node --inspect-brk node_modules/.bin/jest --runInBand",
|
||||
"test:profile": "node --cpu-prof node_modules/.bin/jest --runInBand"
|
||||
"format": "prettier --write ."
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": [
|
||||
|
@ -116,10 +65,29 @@
|
|||
"last 1 safari version"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/plugin-proposal-private-property-in-object": "^7.16.7",
|
||||
"@storybook/addon-actions": "^6.4.22",
|
||||
"@storybook/addon-essentials": "^6.4.22",
|
||||
"@storybook/addon-links": "^6.4.22",
|
||||
"@storybook/builder-webpack5": "^6.4.22",
|
||||
"@storybook/manager-webpack5": "^6.4.22",
|
||||
"@storybook/node-logger": "^6.4.22",
|
||||
"@storybook/preset-create-react-app": "^4.1.0",
|
||||
"@storybook/react": "^6.4.22",
|
||||
"@types/styled-components": "^5.1.24",
|
||||
"@types/webpack": "^5.28.0",
|
||||
"react-codejar": "^1.1.2",
|
||||
"style-loader": "^3.3.1",
|
||||
"ts-loader": "^9.2.8",
|
||||
"webpack": "^5.72.0",
|
||||
"webpack-cli": "^4.9.2",
|
||||
"webpack-dev-server": "^4.8.1"
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/react": "17.0.43"
|
||||
},
|
||||
"source": "./src/index.ts",
|
||||
"main": "./dist/src/index.js",
|
||||
"types": "./dist/src/index.d.ts"
|
||||
"main": "dist/bundle.js",
|
||||
"types": "dist/src/index.d.ts"
|
||||
}
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
module.exports = {
|
||||
plugins: {
|
||||
"postcss-import": {},
|
||||
"tailwindcss/nesting": {},
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
cssnano: {},
|
||||
},
|
||||
};
|
1
packages/components/src/SquiggleChart.js.map
Normal file
1
packages/components/src/SquiggleChart.js.map
Normal file
File diff suppressed because one or more lines are too long
|
@ -1,86 +0,0 @@
|
|||
import * as React from "react";
|
||||
import {
|
||||
XCircleIcon,
|
||||
InformationCircleIcon,
|
||||
CheckCircleIcon,
|
||||
} from "@heroicons/react/solid";
|
||||
import clsx from "clsx";
|
||||
|
||||
export const Alert: React.FC<{
|
||||
heading: string;
|
||||
backgroundColor: string;
|
||||
headingColor: string;
|
||||
bodyColor: string;
|
||||
icon: (props: React.ComponentProps<"svg">) => JSX.Element;
|
||||
iconColor: string;
|
||||
children?: React.ReactNode;
|
||||
}> = ({
|
||||
heading = "Error",
|
||||
backgroundColor,
|
||||
headingColor,
|
||||
bodyColor,
|
||||
icon: Icon,
|
||||
iconColor,
|
||||
children,
|
||||
}) => {
|
||||
return (
|
||||
<div className={clsx("rounded-md p-4", backgroundColor)} role="status">
|
||||
<div className="flex">
|
||||
<Icon
|
||||
className={clsx("h-5 w-5 flex-shrink-0", iconColor)}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
<div className="ml-3 grow">
|
||||
<header className={clsx("text-sm font-medium", headingColor)}>
|
||||
{heading}
|
||||
</header>
|
||||
{children && React.Children.count(children) ? (
|
||||
<div className={clsx("mt-2 text-sm", bodyColor)}>{children}</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const ErrorAlert: React.FC<{
|
||||
heading: string;
|
||||
children?: React.ReactNode;
|
||||
}> = (props) => (
|
||||
<Alert
|
||||
{...props}
|
||||
backgroundColor="bg-red-100"
|
||||
headingColor="text-red-800"
|
||||
bodyColor="text-red-700"
|
||||
icon={XCircleIcon}
|
||||
iconColor="text-red-400"
|
||||
/>
|
||||
);
|
||||
|
||||
export const MessageAlert: React.FC<{
|
||||
heading: string;
|
||||
children?: React.ReactNode;
|
||||
}> = (props) => (
|
||||
<Alert
|
||||
{...props}
|
||||
backgroundColor="bg-slate-100"
|
||||
headingColor="text-slate-700"
|
||||
bodyColor="text-slate-700"
|
||||
icon={InformationCircleIcon}
|
||||
iconColor="text-slate-400"
|
||||
/>
|
||||
);
|
||||
|
||||
export const SuccessAlert: React.FC<{
|
||||
heading: string;
|
||||
children?: React.ReactNode;
|
||||
}> = (props) => (
|
||||
<Alert
|
||||
{...props}
|
||||
backgroundColor="bg-green-50"
|
||||
headingColor="text-green-800"
|
||||
bodyColor="text-green-700"
|
||||
icon={CheckCircleIcon}
|
||||
iconColor="text-green-400"
|
||||
/>
|
||||
);
|
|
@ -1,49 +1,34 @@
|
|||
import _ from "lodash";
|
||||
import React, { FC, useMemo, useRef } from "react";
|
||||
import React, { FC } from "react";
|
||||
import AceEditor from "react-ace";
|
||||
|
||||
import "ace-builds/src-noconflict/mode-golang";
|
||||
import "ace-builds/src-noconflict/theme-github";
|
||||
|
||||
import { SqLocation } from "@quri/squiggle-lang";
|
||||
|
||||
interface CodeEditorProps {
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
onSubmit?: () => void;
|
||||
oneLine?: boolean;
|
||||
width?: number;
|
||||
height: number;
|
||||
showGutter?: boolean;
|
||||
errorLocations?: SqLocation[];
|
||||
}
|
||||
|
||||
export const CodeEditor: FC<CodeEditorProps> = ({
|
||||
export let CodeEditor: FC<CodeEditorProps> = ({
|
||||
value,
|
||||
onChange,
|
||||
onSubmit,
|
||||
height,
|
||||
oneLine = false,
|
||||
showGutter = false,
|
||||
errorLocations = [],
|
||||
}) => {
|
||||
const lineCount = value.split("\n").length;
|
||||
const id = useMemo(() => _.uniqueId(), []);
|
||||
|
||||
// this is necessary because AceEditor binds commands on mount, see https://github.com/securingsincity/react-ace/issues/684
|
||||
const onSubmitRef = useRef<typeof onSubmit | null>(null);
|
||||
onSubmitRef.current = onSubmit;
|
||||
|
||||
const editorEl = useRef<AceEditor | null>(null);
|
||||
|
||||
height,
|
||||
}: CodeEditorProps) => {
|
||||
let lineCount = value.split("\n").length;
|
||||
let id = _.uniqueId();
|
||||
return (
|
||||
<AceEditor
|
||||
ref={editorEl}
|
||||
value={value}
|
||||
mode="golang"
|
||||
theme="github"
|
||||
width="100%"
|
||||
fontSize={14}
|
||||
width={"100%"}
|
||||
height={String(height) + "px"}
|
||||
minLines={oneLine ? lineCount : undefined}
|
||||
maxLines={oneLine ? lineCount : undefined}
|
||||
|
@ -55,22 +40,11 @@ export const CodeEditor: FC<CodeEditorProps> = ({
|
|||
editorProps={{
|
||||
$blockScrolling: true,
|
||||
}}
|
||||
setOptions={{}}
|
||||
commands={[
|
||||
{
|
||||
name: "submit",
|
||||
bindKey: { mac: "Cmd-Enter", win: "Ctrl-Enter" },
|
||||
exec: () => onSubmitRef.current?.(),
|
||||
},
|
||||
]}
|
||||
markers={errorLocations?.map((location) => ({
|
||||
startRow: location.start.line - 1,
|
||||
startCol: location.start.column - 1,
|
||||
endRow: location.end.line - 1,
|
||||
endCol: location.end.column - 1,
|
||||
className: "ace-error-marker",
|
||||
type: "text",
|
||||
}))}
|
||||
setOptions={{
|
||||
enableBasicAutocompletion: false,
|
||||
enableLiveAutocompletion: false,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
||||
export default CodeEditor;
|
||||
|
|
|
@ -1,222 +1,42 @@
|
|||
import * as React from "react";
|
||||
import {
|
||||
SqDistribution,
|
||||
result,
|
||||
SqDistributionError,
|
||||
resultMap,
|
||||
SqRecord,
|
||||
environment,
|
||||
SqDistributionTag,
|
||||
} from "@quri/squiggle-lang";
|
||||
import { Vega } from "react-vega";
|
||||
import { ErrorAlert } from "./Alert";
|
||||
import { useSize } from "react-use";
|
||||
import _ from "lodash";
|
||||
import type { Spec } from "vega";
|
||||
import type { Distribution } from "@quri/squiggle-lang";
|
||||
import { distributionErrorToString } from "@quri/squiggle-lang";
|
||||
import { createClassFromSpec } from "react-vega";
|
||||
import * as chartSpecification from "../vega-specs/spec-distributions.json";
|
||||
import { ErrorBox } from "./ErrorBox";
|
||||
|
||||
import {
|
||||
buildVegaSpec,
|
||||
DistributionChartSpecOptions,
|
||||
} from "../lib/distributionSpecBuilder";
|
||||
import { NumberShower } from "./NumberShower";
|
||||
import { Plot, parsePlot } from "../lib/plotParser";
|
||||
import { flattenResult } from "../lib/utility";
|
||||
import { hasMassBelowZero } from "../lib/distributionUtils";
|
||||
let SquiggleVegaChart = createClassFromSpec({
|
||||
spec: chartSpecification as Spec,
|
||||
});
|
||||
|
||||
export type DistributionPlottingSettings = {
|
||||
/** Whether to show a summary of means, stdev, percentiles etc */
|
||||
showSummary: boolean;
|
||||
actions?: boolean;
|
||||
} & DistributionChartSpecOptions;
|
||||
|
||||
export type DistributionChartProps = {
|
||||
plot: Plot;
|
||||
environment: environment;
|
||||
width?: number;
|
||||
type DistributionChartProps = {
|
||||
distribution: Distribution;
|
||||
width: number;
|
||||
height: number;
|
||||
xAxisType?: "number" | "dateTime";
|
||||
} & DistributionPlottingSettings;
|
||||
|
||||
export function defaultPlot(distribution: SqDistribution): Plot {
|
||||
return { distributions: [{ name: "default", distribution }] };
|
||||
}
|
||||
|
||||
export function makePlot(record: SqRecord): Plot | void {
|
||||
const plotResult = parsePlot(record);
|
||||
if (plotResult.tag === "Ok") {
|
||||
return plotResult.value;
|
||||
}
|
||||
}
|
||||
|
||||
export const DistributionChart: React.FC<DistributionChartProps> = (props) => {
|
||||
const {
|
||||
plot,
|
||||
environment,
|
||||
height,
|
||||
showSummary,
|
||||
width,
|
||||
logX,
|
||||
actions = false,
|
||||
} = props;
|
||||
const [sized] = useSize((size) => {
|
||||
const shapes = flattenResult(
|
||||
plot.distributions.map((x) =>
|
||||
resultMap(x.distribution.pointSet(environment), (pointSet) => ({
|
||||
name: x.name,
|
||||
// color: x.color, // not supported yet
|
||||
...pointSet.asShape(),
|
||||
}))
|
||||
)
|
||||
);
|
||||
|
||||
if (shapes.tag === "Error") {
|
||||
return (
|
||||
<ErrorAlert heading="Distribution Error">
|
||||
{shapes.value.toString()}
|
||||
</ErrorAlert>
|
||||
);
|
||||
}
|
||||
|
||||
// if this is a sample set, include the samples
|
||||
const samples: number[] = [];
|
||||
for (const { distribution } of plot?.distributions) {
|
||||
if (distribution.tag === SqDistributionTag.SampleSet) {
|
||||
samples.push(...distribution.value());
|
||||
}
|
||||
}
|
||||
|
||||
const domain = shapes.value.flatMap((shape) =>
|
||||
shape.discrete.concat(shape.continuous)
|
||||
);
|
||||
|
||||
const spec = buildVegaSpec({
|
||||
...props,
|
||||
minX: props.minX ?? Math.min(...domain.map((x) => x.x)),
|
||||
maxX: props.minX ?? Math.max(...domain.map((x) => x.x)),
|
||||
maxY: Math.max(...domain.map((x) => x.y)),
|
||||
});
|
||||
|
||||
// I think size.width is sometimes not finite due to the component not being in a visible context
|
||||
// This occurs during testing
|
||||
let widthProp = width
|
||||
? width
|
||||
: Number.isFinite(size.width)
|
||||
? size.width
|
||||
: 400;
|
||||
if (widthProp < 20) {
|
||||
console.warn(
|
||||
`Width of Distribution is set to ${widthProp}, which is too small`
|
||||
);
|
||||
widthProp = 20;
|
||||
}
|
||||
|
||||
const vegaData = { data: shapes.value, samples };
|
||||
|
||||
return (
|
||||
<div style={{ width: widthProp }}>
|
||||
{logX && shapes.value.some(hasMassBelowZero) ? (
|
||||
<ErrorAlert heading="Log Domain Error">
|
||||
Cannot graph distribution with negative values on logarithmic scale.
|
||||
</ErrorAlert>
|
||||
) : (
|
||||
<Vega
|
||||
spec={spec}
|
||||
data={vegaData}
|
||||
width={widthProp - 10}
|
||||
height={height}
|
||||
actions={actions}
|
||||
/>
|
||||
)}
|
||||
<div className="flex justify-center">
|
||||
{showSummary && plot.distributions.length === 1 && (
|
||||
<SummaryTable
|
||||
distribution={plot.distributions[0].distribution}
|
||||
environment={environment}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
return sized;
|
||||
};
|
||||
|
||||
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 = {
|
||||
distribution: SqDistribution;
|
||||
environment: environment;
|
||||
};
|
||||
|
||||
const SummaryTable: React.FC<SummaryTableProps> = ({
|
||||
export const DistributionChart: React.FC<DistributionChartProps> = ({
|
||||
distribution,
|
||||
environment,
|
||||
}) => {
|
||||
const mean = distribution.mean(environment);
|
||||
const stdev = distribution.stdev(environment);
|
||||
const p5 = distribution.inv(environment, 0.05);
|
||||
const p10 = distribution.inv(environment, 0.1);
|
||||
const p25 = distribution.inv(environment, 0.25);
|
||||
const p50 = distribution.inv(environment, 0.5);
|
||||
const p75 = distribution.inv(environment, 0.75);
|
||||
const p90 = distribution.inv(environment, 0.9);
|
||||
const p95 = distribution.inv(environment, 0.95);
|
||||
|
||||
const hasResult = (x: result<number, SqDistributionError>): boolean =>
|
||||
x.tag === "Ok";
|
||||
|
||||
const unwrapResult = (
|
||||
x: result<number, SqDistributionError>
|
||||
): React.ReactNode => {
|
||||
if (x.tag === "Ok") {
|
||||
return <NumberShower number={x.value} />;
|
||||
} else {
|
||||
return (
|
||||
<ErrorAlert heading="Distribution Error">
|
||||
{x.value.toString()}
|
||||
</ErrorAlert>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<table className="border border-collapse border-slate-400">
|
||||
<thead className="bg-slate-50">
|
||||
<tr>
|
||||
<TableHeadCell>{"Mean"}</TableHeadCell>
|
||||
{hasResult(stdev) && <TableHeadCell>{"Stdev"}</TableHeadCell>}
|
||||
<TableHeadCell>{"5%"}</TableHeadCell>
|
||||
<TableHeadCell>{"10%"}</TableHeadCell>
|
||||
<TableHeadCell>{"25%"}</TableHeadCell>
|
||||
<TableHeadCell>{"50%"}</TableHeadCell>
|
||||
<TableHeadCell>{"75%"}</TableHeadCell>
|
||||
<TableHeadCell>{"90%"}</TableHeadCell>
|
||||
<TableHeadCell>{"95%"}</TableHeadCell>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<Cell>{unwrapResult(mean)}</Cell>
|
||||
{hasResult(stdev) && <Cell>{unwrapResult(stdev)}</Cell>}
|
||||
<Cell>{unwrapResult(p5)}</Cell>
|
||||
<Cell>{unwrapResult(p10)}</Cell>
|
||||
<Cell>{unwrapResult(p25)}</Cell>
|
||||
<Cell>{unwrapResult(p50)}</Cell>
|
||||
<Cell>{unwrapResult(p75)}</Cell>
|
||||
<Cell>{unwrapResult(p90)}</Cell>
|
||||
<Cell>{unwrapResult(p95)}</Cell>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
);
|
||||
width,
|
||||
height,
|
||||
}: DistributionChartProps) => {
|
||||
let shape = distribution.pointSet();
|
||||
if (shape.tag === "Ok") {
|
||||
return (
|
||||
<SquiggleVegaChart
|
||||
data={{ con: shape.value.continuous, dis: shape.value.discrete }}
|
||||
width={width - 20}
|
||||
height={height}
|
||||
actions={false}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<ErrorBox heading="Distribution Error">
|
||||
{distributionErrorToString(shape.value)}
|
||||
</ErrorBox>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
import type { LogScale, LinearScale, PowScale } from "vega";
|
||||
export let linearXScale: LinearScale = {
|
||||
name: "xscale",
|
||||
type: "linear",
|
||||
range: "width",
|
||||
zero: false,
|
||||
nice: false,
|
||||
domain: {
|
||||
fields: [
|
||||
{
|
||||
data: "con",
|
||||
field: "x",
|
||||
},
|
||||
{
|
||||
data: "dis",
|
||||
field: "x",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
export let linearYScale: LinearScale = {
|
||||
name: "yscale",
|
||||
type: "linear",
|
||||
range: "height",
|
||||
zero: true,
|
||||
domain: {
|
||||
fields: [
|
||||
{
|
||||
data: "con",
|
||||
field: "y",
|
||||
},
|
||||
{
|
||||
data: "dis",
|
||||
field: "y",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export let logXScale: LogScale = {
|
||||
name: "xscale",
|
||||
type: "log",
|
||||
range: "width",
|
||||
zero: false,
|
||||
base: 10,
|
||||
nice: false,
|
||||
domain: {
|
||||
fields: [
|
||||
{
|
||||
data: "con",
|
||||
field: "x",
|
||||
},
|
||||
{
|
||||
data: "dis",
|
||||
field: "x",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export let expYScale: PowScale = {
|
||||
name: "yscale",
|
||||
type: "pow",
|
||||
exponent: 0.1,
|
||||
range: "height",
|
||||
zero: true,
|
||||
nice: false,
|
||||
domain: {
|
||||
fields: [
|
||||
{
|
||||
data: "con",
|
||||
field: "y",
|
||||
},
|
||||
{
|
||||
data: "dis",
|
||||
field: "y",
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
20
packages/components/src/components/ErrorBox.tsx
Normal file
20
packages/components/src/components/ErrorBox.tsx
Normal file
|
@ -0,0 +1,20 @@
|
|||
import * as React from "react";
|
||||
import styled from "styled-components";
|
||||
|
||||
const ShowError = styled.div`
|
||||
border: 1px solid #792e2e;
|
||||
background: #eee2e2;
|
||||
padding: 0.4em 0.8em;
|
||||
`;
|
||||
|
||||
export const ErrorBox: React.FC<{
|
||||
heading: string;
|
||||
children: React.ReactNode;
|
||||
}> = ({ heading = "Error", children }) => {
|
||||
return (
|
||||
<ShowError>
|
||||
<h3>{heading}</h3>
|
||||
{children}
|
||||
</ShowError>
|
||||
);
|
||||
};
|
|
@ -1,107 +1,115 @@
|
|||
import * as React from "react";
|
||||
import {
|
||||
SqLambda,
|
||||
environment,
|
||||
SqValueTag,
|
||||
SqError,
|
||||
} from "@quri/squiggle-lang";
|
||||
import { FunctionChart1Dist } from "./FunctionChart1Dist";
|
||||
import { FunctionChart1Number } from "./FunctionChart1Number";
|
||||
import { DistributionPlottingSettings } from "./DistributionChart";
|
||||
import { MessageAlert } from "./Alert";
|
||||
import { SquiggleErrorAlert } from "./SquiggleErrorAlert";
|
||||
import _ from "lodash";
|
||||
import type { Spec } from "vega";
|
||||
import type { Distribution, errorValue, result } from "@quri/squiggle-lang";
|
||||
import { createClassFromSpec } from "react-vega";
|
||||
import * as percentilesSpec from "../vega-specs/spec-percentiles.json";
|
||||
import { DistributionChart } from "./DistributionChart";
|
||||
import { ErrorBox } from "./ErrorBox";
|
||||
|
||||
export type FunctionChartSettings = {
|
||||
start: number;
|
||||
stop: number;
|
||||
count: number;
|
||||
let SquigglePercentilesChart = createClassFromSpec({
|
||||
spec: percentilesSpec as Spec,
|
||||
});
|
||||
|
||||
type distPlusFn = (a: number) => result<Distribution, errorValue>;
|
||||
|
||||
const _rangeByCount = (start: number, stop: number, count: number) => {
|
||||
const step = (stop - start) / (count - 1);
|
||||
const items = _.range(start, stop, step);
|
||||
const result = items.concat([stop]);
|
||||
return result;
|
||||
};
|
||||
|
||||
interface FunctionChartProps {
|
||||
fn: SqLambda;
|
||||
chartSettings: FunctionChartSettings;
|
||||
distributionPlotSettings: DistributionPlottingSettings;
|
||||
environment: environment;
|
||||
height: number;
|
||||
function unwrap<a, b>(x: result<a, b>): a {
|
||||
if (x.tag === "Ok") {
|
||||
return x.value;
|
||||
} else {
|
||||
throw Error("FAILURE TO UNWRAP");
|
||||
}
|
||||
}
|
||||
|
||||
const FunctionCallErrorAlert = ({ error }: { error: SqError }) => {
|
||||
const [expanded, setExpanded] = React.useState(false);
|
||||
if (expanded) {
|
||||
function mapFilter<a, b>(xs: a[], f: (x: a) => b | undefined): b[] {
|
||||
let initial: b[] = [];
|
||||
return xs.reduce((previous, current) => {
|
||||
let value: b | undefined = f(current);
|
||||
if (value !== undefined) {
|
||||
return previous.concat([value]);
|
||||
} else {
|
||||
return previous;
|
||||
}
|
||||
}, initial);
|
||||
}
|
||||
|
||||
export const FunctionChart: React.FC<{
|
||||
distPlusFn: distPlusFn;
|
||||
diagramStart: number;
|
||||
diagramStop: number;
|
||||
diagramCount: number;
|
||||
}> = ({ distPlusFn, diagramStart, diagramStop, diagramCount }) => {
|
||||
let [mouseOverlay, setMouseOverlay] = React.useState(0);
|
||||
function handleHover(...args) {
|
||||
setMouseOverlay(args[1]);
|
||||
}
|
||||
function handleOut() {
|
||||
setMouseOverlay(NaN);
|
||||
}
|
||||
const signalListeners = { mousemove: handleHover, mouseout: handleOut };
|
||||
let mouseItem = distPlusFn(mouseOverlay);
|
||||
let showChart =
|
||||
mouseItem.tag === "Ok" ? (
|
||||
<DistributionChart
|
||||
distribution={mouseItem.value}
|
||||
width={400}
|
||||
height={140}
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
);
|
||||
let data1 = _rangeByCount(diagramStart, diagramStop, diagramCount);
|
||||
let valueData = mapFilter(data1, (x) => {
|
||||
let result = distPlusFn(x);
|
||||
if (result.tag === "Ok") {
|
||||
return { x: x, value: result.value };
|
||||
}
|
||||
}).map(({ x, value }) => {
|
||||
return {
|
||||
x: x,
|
||||
p1: unwrap(value.inv(0.01)),
|
||||
p5: unwrap(value.inv(0.05)),
|
||||
p10: unwrap(value.inv(0.12)),
|
||||
p20: unwrap(value.inv(0.2)),
|
||||
p30: unwrap(value.inv(0.3)),
|
||||
p40: unwrap(value.inv(0.4)),
|
||||
p50: unwrap(value.inv(0.5)),
|
||||
p60: unwrap(value.inv(0.6)),
|
||||
p70: unwrap(value.inv(0.7)),
|
||||
p80: unwrap(value.inv(0.8)),
|
||||
p90: unwrap(value.inv(0.9)),
|
||||
p95: unwrap(value.inv(0.95)),
|
||||
p99: unwrap(value.inv(0.99)),
|
||||
};
|
||||
});
|
||||
|
||||
let errorData = mapFilter(data1, (x) => {
|
||||
let result = distPlusFn(x);
|
||||
if (result.tag === "Error") {
|
||||
return { x: x, error: result.value };
|
||||
}
|
||||
});
|
||||
let error2 = _.groupBy(errorData, (x) => x.error);
|
||||
return (
|
||||
<MessageAlert heading="Function Display Failed">
|
||||
<div className="space-y-2">
|
||||
<span
|
||||
className="underline decoration-dashed cursor-pointer"
|
||||
onClick={() => setExpanded(!expanded)}
|
||||
>
|
||||
{expanded ? "Hide" : "Show"} error details
|
||||
</span>
|
||||
{expanded ? <SquiggleErrorAlert error={error} /> : null}
|
||||
</div>
|
||||
</MessageAlert>
|
||||
<>
|
||||
<SquigglePercentilesChart
|
||||
data={{ facet: valueData }}
|
||||
actions={false}
|
||||
signalListeners={signalListeners}
|
||||
/>
|
||||
{showChart}
|
||||
{_.keysIn(error2).map((k) => (
|
||||
<ErrorBox heading={k}>
|
||||
{`Values: [${error2[k].map((r) => r.x.toFixed(2)).join(",")}]`}
|
||||
</ErrorBox>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const FunctionChart: React.FC<FunctionChartProps> = ({
|
||||
fn,
|
||||
chartSettings,
|
||||
environment,
|
||||
distributionPlotSettings,
|
||||
height,
|
||||
}) => {
|
||||
console.log(fn.parameters().length);
|
||||
if (fn.parameters().length !== 1) {
|
||||
return (
|
||||
<MessageAlert heading="Function Display Not Supported">
|
||||
Only functions with one parameter are displayed.
|
||||
</MessageAlert>
|
||||
);
|
||||
}
|
||||
const result1 = fn.call([chartSettings.start]);
|
||||
const result2 = fn.call([chartSettings.stop]);
|
||||
const getValidResult = () => {
|
||||
if (result1.tag === "Ok") {
|
||||
return result1;
|
||||
} else if (result2.tag === "Ok") {
|
||||
return result2;
|
||||
} else {
|
||||
return result1;
|
||||
}
|
||||
};
|
||||
const validResult = getValidResult();
|
||||
|
||||
if (validResult.tag === "Error") {
|
||||
return <FunctionCallErrorAlert error={validResult.value} />;
|
||||
}
|
||||
|
||||
switch (validResult.value.tag) {
|
||||
case SqValueTag.Distribution:
|
||||
return (
|
||||
<FunctionChart1Dist
|
||||
fn={fn}
|
||||
chartSettings={chartSettings}
|
||||
environment={environment}
|
||||
height={height}
|
||||
distributionPlotSettings={distributionPlotSettings}
|
||||
/>
|
||||
);
|
||||
case SqValueTag.Number:
|
||||
return (
|
||||
<FunctionChart1Number
|
||||
fn={fn}
|
||||
chartSettings={chartSettings}
|
||||
environment={environment}
|
||||
height={height}
|
||||
/>
|
||||
);
|
||||
default:
|
||||
return (
|
||||
<MessageAlert heading="Function Display Not Supported">
|
||||
There is no function visualization for this type of output:{" "}
|
||||
<span className="font-bold">{validResult.value.tag}</span>
|
||||
</MessageAlert>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,225 +0,0 @@
|
|||
import * as React from "react";
|
||||
import _ from "lodash";
|
||||
import type { Spec } from "vega";
|
||||
import {
|
||||
SqDistribution,
|
||||
result,
|
||||
SqLambda,
|
||||
environment,
|
||||
SqError,
|
||||
SqValue,
|
||||
SqValueTag,
|
||||
} from "@quri/squiggle-lang";
|
||||
import { createClassFromSpec } from "react-vega";
|
||||
import * as percentilesSpec from "../vega-specs/spec-percentiles.json";
|
||||
import {
|
||||
DistributionChart,
|
||||
DistributionPlottingSettings,
|
||||
defaultPlot,
|
||||
} from "./DistributionChart";
|
||||
import { NumberShower } from "./NumberShower";
|
||||
import { ErrorAlert } from "./Alert";
|
||||
|
||||
let SquigglePercentilesChart = createClassFromSpec({
|
||||
spec: percentilesSpec as Spec,
|
||||
});
|
||||
|
||||
const _rangeByCount = (start: number, stop: number, count: number) => {
|
||||
const step = (stop - start) / (count - 1);
|
||||
const items = _.range(start, stop, step);
|
||||
const result = items.concat([stop]);
|
||||
return result;
|
||||
};
|
||||
|
||||
function unwrap<a, b>(x: result<a, b>): a {
|
||||
if (x.tag === "Ok") {
|
||||
return x.value;
|
||||
} else {
|
||||
throw Error("FAILURE TO UNWRAP");
|
||||
}
|
||||
}
|
||||
export type FunctionChartSettings = {
|
||||
start: number;
|
||||
stop: number;
|
||||
count: number;
|
||||
};
|
||||
|
||||
interface FunctionChart1DistProps {
|
||||
fn: SqLambda;
|
||||
chartSettings: FunctionChartSettings;
|
||||
distributionPlotSettings: DistributionPlottingSettings;
|
||||
environment: environment;
|
||||
height: number;
|
||||
}
|
||||
|
||||
type percentiles = {
|
||||
x: number;
|
||||
p1: number;
|
||||
p5: number;
|
||||
p10: number;
|
||||
p20: number;
|
||||
p30: number;
|
||||
p40: number;
|
||||
p50: number;
|
||||
p60: number;
|
||||
p70: number;
|
||||
p80: number;
|
||||
p90: number;
|
||||
p95: number;
|
||||
p99: number;
|
||||
}[];
|
||||
|
||||
type errors = _.Dictionary<
|
||||
{
|
||||
x: number;
|
||||
value: string;
|
||||
}[]
|
||||
>;
|
||||
|
||||
type point = { x: number; value: result<SqDistribution, string> };
|
||||
|
||||
let getPercentiles = ({
|
||||
chartSettings,
|
||||
fn,
|
||||
environment,
|
||||
}: {
|
||||
chartSettings: FunctionChartSettings;
|
||||
fn: SqLambda;
|
||||
environment: environment;
|
||||
}) => {
|
||||
let chartPointsToRender = _rangeByCount(
|
||||
chartSettings.start,
|
||||
chartSettings.stop,
|
||||
chartSettings.count
|
||||
);
|
||||
|
||||
let chartPointsData: point[] = chartPointsToRender.map((x) => {
|
||||
let result = fn.call([x]);
|
||||
if (result.tag === "Ok") {
|
||||
if (result.value.tag === SqValueTag.Distribution) {
|
||||
return { x, value: { tag: "Ok", value: result.value.value } };
|
||||
} else {
|
||||
return {
|
||||
x,
|
||||
value: {
|
||||
tag: "Error",
|
||||
value:
|
||||
"Cannot currently render functions that don't return distributions",
|
||||
},
|
||||
};
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
x,
|
||||
value: { tag: "Error", value: result.value.toString() },
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
let initialPartition: [
|
||||
{ x: number; value: SqDistribution }[],
|
||||
{ x: number; value: string }[]
|
||||
] = [[], []];
|
||||
|
||||
let [functionImage, errors] = chartPointsData.reduce((acc, current) => {
|
||||
if (current.value.tag === "Ok") {
|
||||
acc[0].push({ x: current.x, value: current.value.value });
|
||||
} else {
|
||||
acc[1].push({ x: current.x, value: current.value.value });
|
||||
}
|
||||
return acc;
|
||||
}, initialPartition);
|
||||
|
||||
let groupedErrors: errors = _.groupBy(errors, (x) => x.value);
|
||||
|
||||
let percentiles: percentiles = functionImage.map(({ x, value }) => {
|
||||
const res = {
|
||||
x: x,
|
||||
p1: unwrap(value.inv(environment, 0.01)),
|
||||
p5: unwrap(value.inv(environment, 0.05)),
|
||||
p10: unwrap(value.inv(environment, 0.1)),
|
||||
p20: unwrap(value.inv(environment, 0.2)),
|
||||
p30: unwrap(value.inv(environment, 0.3)),
|
||||
p40: unwrap(value.inv(environment, 0.4)),
|
||||
p50: unwrap(value.inv(environment, 0.5)),
|
||||
p60: unwrap(value.inv(environment, 0.6)),
|
||||
p70: unwrap(value.inv(environment, 0.7)),
|
||||
p80: unwrap(value.inv(environment, 0.8)),
|
||||
p90: unwrap(value.inv(environment, 0.9)),
|
||||
p95: unwrap(value.inv(environment, 0.95)),
|
||||
p99: unwrap(value.inv(environment, 0.99)),
|
||||
};
|
||||
return res;
|
||||
});
|
||||
|
||||
return { percentiles, errors: groupedErrors };
|
||||
};
|
||||
|
||||
export const FunctionChart1Dist: React.FC<FunctionChart1DistProps> = ({
|
||||
fn,
|
||||
chartSettings,
|
||||
environment,
|
||||
distributionPlotSettings,
|
||||
height,
|
||||
}) => {
|
||||
let [mouseOverlay, setMouseOverlay] = React.useState(0);
|
||||
function handleHover(_name: string, value: unknown) {
|
||||
setMouseOverlay(value as number);
|
||||
}
|
||||
function handleOut() {
|
||||
setMouseOverlay(NaN);
|
||||
}
|
||||
const signalListeners = { mousemove: handleHover, mouseout: handleOut };
|
||||
|
||||
//TODO: This custom error handling is a bit hacky and should be improved.
|
||||
let mouseItem: result<SqValue, SqError> = !!mouseOverlay
|
||||
? fn.call([mouseOverlay])
|
||||
: {
|
||||
tag: "Error",
|
||||
value: SqError.createOtherError(
|
||||
"Hover x-coordinate returned NaN. Expected a number."
|
||||
),
|
||||
};
|
||||
let showChart =
|
||||
mouseItem.tag === "Ok" &&
|
||||
mouseItem.value.tag === SqValueTag.Distribution ? (
|
||||
<DistributionChart
|
||||
plot={defaultPlot(mouseItem.value.value)}
|
||||
environment={environment}
|
||||
width={400}
|
||||
height={50}
|
||||
{...distributionPlotSettings}
|
||||
/>
|
||||
) : null;
|
||||
|
||||
let getPercentilesMemoized = React.useMemo(
|
||||
() => getPercentiles({ chartSettings, fn, environment }),
|
||||
[environment, fn]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SquigglePercentilesChart
|
||||
data={{ facet: getPercentilesMemoized.percentiles }}
|
||||
height={height}
|
||||
actions={false}
|
||||
signalListeners={signalListeners}
|
||||
/>
|
||||
{showChart}
|
||||
{_.entries(getPercentilesMemoized.errors).map(
|
||||
([errorName, errorPoints]) => (
|
||||
<ErrorAlert key={errorName} heading={errorName}>
|
||||
Values:{" "}
|
||||
{errorPoints
|
||||
.map((r, i) => <NumberShower key={i} number={r.x} />)
|
||||
.reduce((a, b) => (
|
||||
<>
|
||||
{a}, {b}
|
||||
</>
|
||||
))}
|
||||
</ErrorAlert>
|
||||
)
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
|
@ -1,119 +0,0 @@
|
|||
import * as React from "react";
|
||||
import _ from "lodash";
|
||||
import type { Spec } from "vega";
|
||||
import { result, SqLambda, environment, SqValueTag } from "@quri/squiggle-lang";
|
||||
import { createClassFromSpec } from "react-vega";
|
||||
import * as lineChartSpec from "../vega-specs/spec-line-chart.json";
|
||||
import { ErrorAlert } from "./Alert";
|
||||
import { squiggleValueTag } from "@quri/squiggle-lang/src/rescript/ForTS/ForTS_SquiggleValue/ForTS_SquiggleValue_tag";
|
||||
|
||||
let SquiggleLineChart = createClassFromSpec({
|
||||
spec: lineChartSpec as Spec,
|
||||
});
|
||||
|
||||
const _rangeByCount = (start: number, stop: number, count: number) => {
|
||||
const step = (stop - start) / (count - 1);
|
||||
const items = _.range(start, stop, step);
|
||||
const result = items.concat([stop]);
|
||||
return result;
|
||||
};
|
||||
|
||||
export type FunctionChartSettings = {
|
||||
start: number;
|
||||
stop: number;
|
||||
count: number;
|
||||
};
|
||||
|
||||
interface FunctionChart1NumberProps {
|
||||
fn: SqLambda;
|
||||
chartSettings: FunctionChartSettings;
|
||||
environment: environment;
|
||||
height: number;
|
||||
}
|
||||
|
||||
type point = { x: number; value: result<number, string> };
|
||||
|
||||
let getFunctionImage = ({
|
||||
chartSettings,
|
||||
fn,
|
||||
environment,
|
||||
}: {
|
||||
chartSettings: FunctionChartSettings;
|
||||
fn: SqLambda;
|
||||
environment: environment;
|
||||
}) => {
|
||||
let chartPointsToRender = _rangeByCount(
|
||||
chartSettings.start,
|
||||
chartSettings.stop,
|
||||
chartSettings.count
|
||||
);
|
||||
|
||||
let chartPointsData: point[] = chartPointsToRender.map((x) => {
|
||||
let result = fn.call([x]);
|
||||
if (result.tag === "Ok") {
|
||||
if (result.value.tag === SqValueTag.Number) {
|
||||
return { x, value: { tag: "Ok", value: result.value.value } };
|
||||
} else {
|
||||
return {
|
||||
x,
|
||||
value: {
|
||||
tag: "Error",
|
||||
value: "This component expected number outputs",
|
||||
},
|
||||
};
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
x,
|
||||
value: { tag: "Error", value: result.value.toString() },
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
let initialPartition: [
|
||||
{ x: number; value: number }[],
|
||||
{ x: number; value: string }[]
|
||||
] = [[], []];
|
||||
|
||||
let [functionImage, errors] = chartPointsData.reduce((acc, current) => {
|
||||
if (current.value.tag === "Ok") {
|
||||
acc[0].push({ x: current.x, value: current.value.value });
|
||||
} else {
|
||||
acc[1].push({ x: current.x, value: current.value.value });
|
||||
}
|
||||
return acc;
|
||||
}, initialPartition);
|
||||
|
||||
return { errors, functionImage };
|
||||
};
|
||||
|
||||
export const FunctionChart1Number: React.FC<FunctionChart1NumberProps> = ({
|
||||
fn,
|
||||
chartSettings,
|
||||
environment,
|
||||
height,
|
||||
}: FunctionChart1NumberProps) => {
|
||||
let getFunctionImageMemoized = React.useMemo(
|
||||
() => getFunctionImage({ chartSettings, fn, environment }),
|
||||
[environment, fn]
|
||||
);
|
||||
|
||||
let data = getFunctionImageMemoized.functionImage.map(({ x, value }) => ({
|
||||
x,
|
||||
y: value,
|
||||
}));
|
||||
return (
|
||||
<>
|
||||
<SquiggleLineChart
|
||||
data={{ facet: data }}
|
||||
height={height}
|
||||
actions={false}
|
||||
/>
|
||||
{getFunctionImageMemoized.errors.map(({ x, value }) => (
|
||||
<ErrorAlert key={x} heading={value}>
|
||||
Error at point ${x}
|
||||
</ErrorAlert>
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
|
@ -1,49 +0,0 @@
|
|||
import _ from "lodash";
|
||||
import React, { FC } from "react";
|
||||
import AceEditor from "react-ace";
|
||||
|
||||
import "ace-builds/src-noconflict/mode-json";
|
||||
import "ace-builds/src-noconflict/theme-github";
|
||||
|
||||
interface CodeEditorProps {
|
||||
value: string;
|
||||
onChange: (value: string) => void;
|
||||
oneLine?: boolean;
|
||||
width?: number;
|
||||
height: number;
|
||||
showGutter?: boolean;
|
||||
}
|
||||
|
||||
export const JsonEditor: FC<CodeEditorProps> = ({
|
||||
value,
|
||||
onChange,
|
||||
oneLine = false,
|
||||
showGutter = false,
|
||||
height,
|
||||
}) => {
|
||||
const lineCount = value.split("\n").length;
|
||||
const id = _.uniqueId();
|
||||
return (
|
||||
<AceEditor
|
||||
value={value}
|
||||
mode="json"
|
||||
theme="github"
|
||||
width={"100%"}
|
||||
height={String(height) + "px"}
|
||||
minLines={oneLine ? lineCount : undefined}
|
||||
maxLines={oneLine ? lineCount : undefined}
|
||||
showGutter={showGutter}
|
||||
highlightActiveLine={false}
|
||||
showPrintMargin={false}
|
||||
onChange={onChange}
|
||||
name={id}
|
||||
editorProps={{
|
||||
$blockScrolling: true,
|
||||
}}
|
||||
setOptions={{
|
||||
enableBasicAutocompletion: false,
|
||||
enableLiveAutocompletion: false,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
};
|
|
@ -1,4 +1,5 @@
|
|||
import * as React from "react";
|
||||
import _ from "lodash";
|
||||
|
||||
const orderOfMagnitudeNum = (n: number) => {
|
||||
return Math.pow(10, n);
|
||||
|
@ -73,23 +74,25 @@ export interface NumberShowerProps {
|
|||
precision?: number;
|
||||
}
|
||||
|
||||
export const NumberShower: React.FC<NumberShowerProps> = ({
|
||||
export let NumberShower: React.FC<NumberShowerProps> = ({
|
||||
number,
|
||||
precision = 2,
|
||||
}) => {
|
||||
const numberWithPresentation = numberShow(number, precision);
|
||||
}: NumberShowerProps) => {
|
||||
let numberWithPresentation = numberShow(number, precision);
|
||||
return (
|
||||
<span>
|
||||
{numberWithPresentation.value}
|
||||
{numberWithPresentation.symbol}
|
||||
{numberWithPresentation.power ? (
|
||||
<span>
|
||||
{"\u00b7" /* dot symbol */}10
|
||||
{"\u00b710"}
|
||||
<span style={{ fontSize: "0.6em", verticalAlign: "super" }}>
|
||||
{numberWithPresentation.power}
|
||||
</span>
|
||||
</span>
|
||||
) : null}
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,158 +1,174 @@
|
|||
import * as React from "react";
|
||||
import _ from "lodash";
|
||||
import styled from "styled-components";
|
||||
import {
|
||||
SqValue,
|
||||
environment,
|
||||
SqProject,
|
||||
defaultEnvironment,
|
||||
run,
|
||||
errorValueToString,
|
||||
squiggleExpression,
|
||||
} from "@quri/squiggle-lang";
|
||||
import { useSquiggle } from "../lib/hooks";
|
||||
import { SquiggleViewer } from "./SquiggleViewer";
|
||||
import { JsImports } from "../lib/jsImports";
|
||||
import { getValueToRender } from "../lib/utility";
|
||||
import type { samplingParams } from "@quri/squiggle-lang";
|
||||
import { NumberShower } from "./NumberShower";
|
||||
import { DistributionChart } from "./DistributionChart";
|
||||