diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 728a8c1c..13234dce 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -9,22 +9,22 @@ # This also holds true for GitHub teams. # Rescript -*.res @OAGr -*.resi @OAGr +*.res @berekuk @OAGr +*.resi @berekuk @OAGr # Typescript -*.tsx @Hazelfire @OAGr -*.ts @Hazelfire @OAGr +*.tsx @Hazelfire @berekuk @OAGr +*.ts @Hazelfire @berekuk @OAGr # Javascript -*.js @Hazelfire @OAGr +*.js @Hazelfire @berekuk @OAGr # Any opsy files -.github/** @quinn-dougherty @OAGr -*.json @quinn-dougherty @Hazelfire @OAGr -*.y*ml @quinn-dougherty @OAGr -*.config.js @Hazelfire @OAGr -netlify.toml @quinn-dougherty @OAGr @Hazelfire +.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 # Documentation *.md @quinn-dougherty @OAGr @Hazelfire diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 4e459652..2f344116 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -12,9 +12,13 @@ updates: commit-message: prefix: "⬆️" open-pull-requests-limit: 100 + labels: + - "dependencies" - package-ecosystem: "github-actions" directory: "/" schedule: interval: "weekly" commit-message: prefix: "⬆️" + labels: + - "dependencies" diff --git a/.github/workflows/ci-cachix.yml b/.github/workflows/ci-cachix.yml new file mode 100644 index 00000000..dfcee3d8 --- /dev/null +++ b/.github/workflows/ci-cachix.yml @@ -0,0 +1,87 @@ +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 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8150d00a..7c0f11e7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,4 @@ -name: Squiggle packages check +name: Squiggle packages checks on: push: @@ -9,213 +9,40 @@ on: branches: - master - develop - - reducer-dev + +env: + TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }} + TURBO_TEAM: quantified-uncertainty jobs: - pre_check: - name: Precheck for skipping redundant jobs + build-test-lint: + name: Build, test, lint 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@v4.0.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@v4.0.0 - with: - paths: '["packages/components/**"]' - - id: skip_website_check - name: Check if the changes are about website src files - uses: fkirc/skip-duplicate-actions@v4.0.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@v4.0.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@v4.0.0 - with: - paths: '["packages/cli/**"]' - - 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 - - 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 + - name: Setup Node.js environment + uses: actions/setup-node@v3 with: - dry: true - prettier_options: --check packages/squiggle-lang + node-version: 16 + cache: 'yarn' + - name: Install dependencies + run: yarn --frozen-lockfile + - name: Turbo run + run: npx turbo run build test lint bundle - lang-build-test-bundle: - name: Language build, test, and bundle + coverage: + name: Coverage 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 with: fetch-depth: 2 - - 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@v3 - - name: Check javascript, typescript, and markdown lint - uses: creyD/prettier_action@v4.2 + - name: Setup Node.js environment + uses: actions/setup-node@v2 with: - dry: true - prettier_options: --check packages/components --ignore-path packages/components/.prettierignore - - 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@v3 - - 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@v3 - - 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@v3 - - name: Install dependencies from monorepo level - run: cd ../../ && yarn - - name: Build rescript in squiggle-lang - run: cd ../squiggle-lang && yarn build - - name: Build components - run: cd ../components && yarn build - - name: Build website assets - run: yarn build - - vscode-ext-lint: - name: VS Code extension lint - runs-on: ubuntu-latest - needs: pre_check - if: ${{ needs.pre_check.outputs.should_skip_vscodeext != 'true' }} - defaults: - run: - shell: bash - working-directory: packages/vscode-ext - steps: - - uses: actions/checkout@v3 - - name: Install dependencies from monorepo level - run: cd ../../ && yarn - - name: Lint the VSCode Extension source code - run: yarn lint - - vscode-ext-build: - name: VS Code extension 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') }} || (needs.pre_check.outputs.should_skip_vscodeext != 'true') }} - defaults: - run: - shell: bash - working-directory: packages/vscode-ext - steps: - - uses: actions/checkout@v3 - - name: Install dependencies from monorepo level - run: cd ../../ && yarn - - name: Build - run: yarn compile - - cli-lint: - name: CLI lint - runs-on: ubuntu-latest - needs: pre_check - if: ${{ needs.pre_check.outputs.should_skip_cli != 'true' }} - defaults: - run: - shell: bash - working-directory: packages/cli - steps: - - uses: actions/checkout@v3 - - name: Check javascript, typescript, and markdown lint - uses: creyD/prettier_action@v4.2 - with: - dry: true - prettier_options: --check packages/cli + node-version: 16 + cache: 'yarn' + - name: Install dependencies + run: yarn + - name: Coverage + run: npx turbo run coverage diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index f4bbbf9e..0fbed1ba 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -3,7 +3,7 @@ name: Run Release Please on: push: branches: - - develop + - master jobs: pre_check: @@ -18,27 +18,27 @@ jobs: steps: - id: skip_lang_check name: Check if the changes are about squiggle-lang src files - uses: fkirc/skip-duplicate-actions@v4.0.0 + 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@v4.0.0 + 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@v4.0.0 + 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@v4.0.0 + 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@v4.0.0 + uses: fkirc/skip-duplicate-actions@v5.2.0 with: paths: '["packages/cli/**"]' @@ -55,21 +55,22 @@ jobs: token: ${{secrets.GITHUB_TOKEN}} command: manifest-pr path: packages/squiggle-lang - bump-patch-for-minor-pre-major: true + # bump-patch-for-minor-pre-major: true skip-github-release: true - # - name: Publish: Checkout source - # uses: actions/checkout@v2 - # # 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 }} + - 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 @@ -82,20 +83,20 @@ jobs: token: ${{secrets.GITHUB_TOKEN}} command: manifest-pr path: packages/components - bump-patch-for-minor-pre-major: true + # bump-patch-for-minor-pre-major: true skip-github-release: true - # - name: Publish: Checkout source - # uses: actions/checkout@v2 - # # 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}} + - 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 @@ -108,7 +109,7 @@ jobs: token: ${{secrets.GITHUB_TOKEN}} command: manifest-pr path: packages/website - bump-patch-for-minor-pre-major: true + # bump-patch-for-minor-pre-major: true skip-github-release: true relplz-vscodeext: name: for vscode-ext @@ -122,7 +123,7 @@ jobs: token: ${{secrets.GITHUB_TOKEN}} command: manifest-pr path: packages/vscode-ext - bump-patch-for-minor-pre-major: true + # bump-patch-for-minor-pre-major: true skip-github-release: true relplz-cl: name: for cli diff --git a/.gitignore b/.gitignore index 5b48f91c..3cc94af0 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,9 @@ yarn-error.log **/.sync.ffs_db .direnv .log + +.vscode +todo.txt +result +shell.nix +.turbo diff --git a/.prettierignore b/.prettierignore index 8090b3f3..ba58d386 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,15 +1,16 @@ .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 diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 1f1ac6f3..7a9992fa 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,7 +1,7 @@ { "packages/cli": "0.0.3", - "packages/components": "0.3.1", - "packages/squiggle-lang": "0.3.0", - "packages/vscode-ext": "0.3.1", - "packages/website": "0.3.0" + "packages/components": "0.4.1", + "packages/squiggle-lang": "0.4.1", + "packages/vscode-ext": "0.4.1", + "packages/website": "0.0.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..f7b0d07a --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1 @@ +See the [Changelog.mdx page](./packages/website/docs/Changelog.mdx) for the changelog. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8a3b026a..452fb0c2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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 Quinn, 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 Slava, 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 netlify, and it should only concern Quinn, Sam, and Ozzie. +We use Vercel, and it should only concern Slava, 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: Quinn and Ozzie are reviewers +- For rescript code: Slava and Ozzie are reviewers - For js or typescript code: Sam and Ozzie are reviewers -- For ops code (i.e. yaml, package.json): Quinn and Sam are reviewers +- For ops code (i.e. yaml, package.json): Slava 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. diff --git a/README.md b/README.md index e182f539..9be8b2b2 100644 --- a/README.md +++ b/README.md @@ -21,10 +21,10 @@ _An estimation language_. ## Our deployments -- **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/ +- **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 - **legacy (2020) playground**: https://playground.squiggle-language.com ## Packages @@ -51,7 +51,19 @@ For any project in the repo, begin by running `yarn` in the top level yarn ``` -See `packages/*/README.md` to work with whatever project you're interested in. +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. # Contributing diff --git a/flake.lock b/flake.lock new file mode 100644 index 00000000..67f81079 --- /dev/null +++ b/flake.lock @@ -0,0 +1,79 @@ +{ + "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 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 00000000..97bcf485 --- /dev/null +++ b/flake.nix @@ -0,0 +1,99 @@ +{ + 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); +} diff --git a/nix/README.md b/nix/README.md new file mode 100644 index 00000000..6ad6a456 --- /dev/null +++ b/nix/README.md @@ -0,0 +1 @@ +Visit `quantified-uncertainty.cachix.org` for information about how to add our binary cache to your local dev environment. diff --git a/nix/shell.nix b/nix/shell.nix new file mode 100644 index 00000000..26f62625 --- /dev/null +++ b/nix/shell.nix @@ -0,0 +1,25 @@ +{ 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 ]; + }; +} diff --git a/nix/squiggle-cli.nix b/nix/squiggle-cli.nix new file mode 100644 index 00000000..4dd7998b --- /dev/null +++ b/nix/squiggle-cli.nix @@ -0,0 +1,13 @@ +{ 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"; + }; +} diff --git a/nix/squiggle-components.nix b/nix/squiggle-components.nix new file mode 100644 index 00000000..3a01641f --- /dev/null +++ b/nix/squiggle-components.nix @@ -0,0 +1,75 @@ +{ 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 + ''; + }; +} diff --git a/nix/squiggle-lang.nix b/nix/squiggle-lang.nix new file mode 100644 index 00000000..0adfae47 --- /dev/null +++ b/nix/squiggle-lang.nix @@ -0,0 +1,116 @@ +{ 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 + ''; + }; + +} diff --git a/nix/squiggle-vscode.nix b/nix/squiggle-vscode.nix new file mode 100644 index 00000000..2e725261 --- /dev/null +++ b/nix/squiggle-vscode.nix @@ -0,0 +1,24 @@ +{ 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"; + }; +} diff --git a/nix/squiggle-website.nix b/nix/squiggle-website.nix new file mode 100644 index 00000000..3209affd --- /dev/null +++ b/nix/squiggle-website.nix @@ -0,0 +1,30 @@ +{ 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"; + }; +} diff --git a/nixos.sh b/nixos.sh index 91aa754f..28ff5d91 100755 --- a/nixos.sh +++ b/nixos.sh @@ -5,14 +5,14 @@ # We need to patchelf rescript executables. https://github.com/NixOS/nixpkgs/issues/107375 set -x -fhsShellName="squiggle-development" -fhsShellDotNix="{pkgs ? import {} }: (pkgs.buildFHSUserEnv { name = \"${fhsShellName}\"; targetPkgs = pkgs: [pkgs.yarn]; runScript = \"yarn\"; }).env" +fhsShellName="squiggle-fhs-development" +fhsShellDotNix="{pkgs ? import {} }: (pkgs.buildFHSUserEnv { name = \"${fhsShellName}\"; targetPkgs = pkgs: [pkgs.yarn pkgs.glibc]; 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 --set-interpreter $theLd ./node_modules/bisect_ppx/bisect-ppx-report +theSo=$(find /nix/store/*$fhsShellName*/lib64 -name libstdc++.so.6 | head -n 1) patchelf --replace-needed libstdc++.so.6 $theSo ./node_modules/rescript/linux/ninja.exe diff --git a/package.json b/package.json index dcab983e..f1241ebe 100644 --- a/package.json +++ b/package.json @@ -2,12 +2,11 @@ "private": true, "name": "squiggle", "scripts": { - "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" + "nodeclean": "rm -r node_modules && rm -r packages/*/node_modules" }, "devDependencies": { - "prettier": "^2.7.1" + "prettier": "^2.7.1", + "turbo": "^1.5.5" }, "workspaces": [ "packages/*" diff --git a/packages/cli/README.md b/packages/cli/README.md index 7b0d0038..ec9e334b 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -20,3 +20,30 @@ 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. diff --git a/packages/cli/package.json b/packages/cli/package.json index 2890d2a4..a21a9939 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -7,13 +7,15 @@ "bin": "index.js", "type": "module", "scripts": { - "start": "node ." + "start": "node .", + "lint": "prettier --check .", + "format": "prettier --write ." }, "license": "MIT", "dependencies": { - "chalk": "^5.0.1", + "chalk": "^5.1.0", "chokidar": "^3.5.3", - "commander": "^9.4.0", + "commander": "^9.4.1", "fs": "^0.0.1-security", "glob": "^8.0.3", "indent-string": "^5.0.0" diff --git a/packages/components/jest.config.js b/packages/components/jest.config.js new file mode 100644 index 00000000..223b20e6 --- /dev/null +++ b/packages/components/jest.config.js @@ -0,0 +1,6 @@ +/** @type {import('ts-jest').JestConfigWithTsJest} */ +module.exports = { + preset: "ts-jest", + setupFilesAfterEnv: ["/test/setup.js"], + testEnvironment: "jsdom", +}; diff --git a/packages/components/netlify.toml b/packages/components/netlify.toml deleted file mode 100644 index d6e5474d..00000000 --- a/packages/components/netlify.toml +++ /dev/null @@ -1,8 +0,0 @@ -[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" diff --git a/packages/components/package.json b/packages/components/package.json index 77e5e263..2669594c 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -1,64 +1,73 @@ { "name": "@quri/squiggle-components", - "version": "0.3.1", + "version": "0.5.0", "license": "MIT", "dependencies": { "@floating-ui/react-dom": "^1.0.0", - "@floating-ui/react-dom-interactions": "^0.9.2", - "@headlessui/react": "^1.6.6", + "@floating-ui/react-dom-interactions": "^0.10.1", + "@headlessui/react": "^1.7.3", "@heroicons/react": "^1.0.6", - "@hookform/resolvers": "^2.9.7", - "@quri/squiggle-lang": "^0.3.0", + "@hookform/resolvers": "^2.9.8", + "@quri/squiggle-lang": "^0.5.0", "@react-hook/size": "^2.1.2", + "@types/uuid": "^8.3.4", "clsx": "^1.2.1", - "framer-motion": "^7.2.0", + "framer-motion": "^7.5.3", "lodash": "^4.17.21", "react": "^18.1.0", "react-ace": "^10.1.0", - "react-hook-form": "^7.34.2", + "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.3", + "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.9", - "@storybook/addon-essentials": "^6.5.10", - "@storybook/addon-links": "^6.5.10", - "@storybook/builder-webpack5": "^6.5.10", - "@storybook/manager-webpack5": "^6.5.10", + "@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.10", + "@storybook/react": "^6.5.12", "@testing-library/jest-dom": "^5.16.5", - "@testing-library/react": "^13.3.0", + "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^14.4.3", "@types/jest": "^27.5.0", - "@types/lodash": "^4.14.184", - "@types/node": "^18.7.9", - "@types/react": "^18.0.9", + "@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", "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": "^14.1.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-loader": "^9.3.0", + "ts-jest": "^29.0.3", + "ts-loader": "^9.4.1", "tsconfig-paths-webpack-plugin": "^4.0.0", - "typescript": "^4.7.4", - "web-vitals": "^2.1.4", + "typescript": "^4.8.4", + "web-vitals": "^3.0.3", "webpack": "^5.74.0", "webpack-cli": "^4.10.0", - "webpack-dev-server": "^4.10.0" + "webpack-dev-server": "^4.11.1" }, "peerDependencies": { "react": "^16.8.0 || ^17 || ^18", @@ -66,7 +75,7 @@ }, "scripts": { "start": "cross-env REACT_APP_FAST_REFRESH=false && start-storybook -p 6006 -s public", - "build:cjs": "tsc -b", + "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", @@ -74,7 +83,10 @@ "all": "yarn bundle && yarn build", "lint": "prettier --check .", "format": "prettier --write .", - "prepack": "yarn bundle && tsc -b" + "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" }, "eslintConfig": { "extends": [ diff --git a/packages/components/src/components/Alert.tsx b/packages/components/src/components/Alert.tsx index bc2e2f92..cb579536 100644 --- a/packages/components/src/components/Alert.tsx +++ b/packages/components/src/components/Alert.tsx @@ -30,7 +30,7 @@ export const Alert: React.FC<{ className={clsx("h-5 w-5 flex-shrink-0", iconColor)} aria-hidden="true" /> -
+
{heading}
diff --git a/packages/components/src/components/CodeEditor.tsx b/packages/components/src/components/CodeEditor.tsx index 15802131..ec2fdee7 100644 --- a/packages/components/src/components/CodeEditor.tsx +++ b/packages/components/src/components/CodeEditor.tsx @@ -5,6 +5,8 @@ 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; @@ -13,15 +15,17 @@ interface CodeEditorProps { width?: number; height: number; showGutter?: boolean; + errorLocations?: SqLocation[]; } export const CodeEditor: FC = ({ value, onChange, onSubmit, + height, oneLine = false, showGutter = false, - height, + errorLocations = [], }) => { const lineCount = value.split("\n").length; const id = useMemo(() => _.uniqueId(), []); @@ -30,8 +34,11 @@ export const CodeEditor: FC = ({ const onSubmitRef = useRef(null); onSubmitRef.current = onSubmit; + const editorEl = useRef(null); + return ( = ({ 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", + }))} /> ); }; diff --git a/packages/components/src/components/DistributionChart.tsx b/packages/components/src/components/DistributionChart.tsx index 79536e12..3f1b8567 100644 --- a/packages/components/src/components/DistributionChart.tsx +++ b/packages/components/src/components/DistributionChart.tsx @@ -1,11 +1,12 @@ import * as React from "react"; import { - Distribution, + SqDistribution, result, - distributionError, - distributionErrorToString, - squiggleExpression, + SqDistributionError, resultMap, + SqRecord, + environment, + SqDistributionTag, } from "@quri/squiggle-lang"; import { Vega } from "react-vega"; import { ErrorAlert } from "./Alert"; @@ -28,17 +29,17 @@ export type DistributionPlottingSettings = { export type DistributionChartProps = { plot: Plot; + environment: environment; width?: number; height: number; + xAxisType?: "number" | "dateTime"; } & DistributionPlottingSettings; -export function defaultPlot(distribution: Distribution): Plot { +export function defaultPlot(distribution: SqDistribution): Plot { return { distributions: [{ name: "default", distribution }] }; } -export function makePlot(record: { - [key: string]: squiggleExpression; -}): Plot | void { +export function makePlot(record: SqRecord): Plot | void { const plotResult = parsePlot(record); if (plotResult.tag === "Ok") { return plotResult.value; @@ -46,38 +47,68 @@ export function makePlot(record: { } export const DistributionChart: React.FC = (props) => { - const { plot, height, showSummary, width, logX, actions = false } = props; + const { + plot, + environment, + height, + showSummary, + width, + logX, + actions = false, + } = props; const [sized] = useSize((size) => { - let shapes = flattenResult( + const shapes = flattenResult( plot.distributions.map((x) => - resultMap(x.distribution.pointSet(), (shape) => ({ + resultMap(x.distribution.pointSet(environment), (pointSet) => ({ name: x.name, // color: x.color, // not supported yet - continuous: shape.continuous, - discrete: shape.discrete, + ...pointSet.asShape(), })) ) ); + if (shapes.tag === "Error") { return ( - {distributionErrorToString(shapes.value)} + {shapes.value.toString()} ); } - const spec = buildVegaSpec(props); + // 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()); + } + } - let widthProp = width ? width : size.width; + 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 domain = shapes.value.flatMap((shape) => - shape.discrete.concat(shape.continuous) - ); + + const vegaData = { data: shapes.value, samples }; return (
@@ -88,7 +119,7 @@ export const DistributionChart: React.FC = (props) => { ) : ( = (props) => { )}
{showSummary && plot.distributions.length === 1 && ( - + )}
@@ -120,32 +154,36 @@ const Cell: React.FC<{ children: React.ReactNode }> = ({ children }) => ( ); type SummaryTableProps = { - distribution: Distribution; + distribution: SqDistribution; + environment: environment; }; -const SummaryTable: React.FC = ({ distribution }) => { - const mean = distribution.mean(); - const stdev = distribution.stdev(); - const p5 = distribution.inv(0.05); - const p10 = distribution.inv(0.1); - const p25 = distribution.inv(0.25); - const p50 = distribution.inv(0.5); - const p75 = distribution.inv(0.75); - const p90 = distribution.inv(0.9); - const p95 = distribution.inv(0.95); +const SummaryTable: React.FC = ({ + 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): boolean => + const hasResult = (x: result): boolean => x.tag === "Ok"; const unwrapResult = ( - x: result + x: result ): React.ReactNode => { if (x.tag === "Ok") { return ; } else { return ( - {distributionErrorToString(x.value)} + {x.value.toString()} ); } diff --git a/packages/components/src/components/FunctionChart.tsx b/packages/components/src/components/FunctionChart.tsx index 73378cd8..fda699e9 100644 --- a/packages/components/src/components/FunctionChart.tsx +++ b/packages/components/src/components/FunctionChart.tsx @@ -1,14 +1,15 @@ import * as React from "react"; import { - lambdaValue, + SqLambda, environment, - runForeign, - errorValueToString, + SqValueTag, + SqError, } from "@quri/squiggle-lang"; import { FunctionChart1Dist } from "./FunctionChart1Dist"; import { FunctionChart1Number } from "./FunctionChart1Number"; import { DistributionPlottingSettings } from "./DistributionChart"; -import { ErrorAlert, MessageAlert } from "./Alert"; +import { MessageAlert } from "./Alert"; +import { SquiggleErrorAlert } from "./SquiggleErrorAlert"; export type FunctionChartSettings = { start: number; @@ -17,13 +18,32 @@ export type FunctionChartSettings = { }; interface FunctionChartProps { - fn: lambdaValue; + fn: SqLambda; chartSettings: FunctionChartSettings; distributionPlotSettings: DistributionPlottingSettings; environment: environment; height: number; } +const FunctionCallErrorAlert = ({ error }: { error: SqError }) => { + const [expanded, setExpanded] = React.useState(false); + if (expanded) { + } + return ( + +
+ setExpanded(!expanded)} + > + {expanded ? "Hide" : "Show"} error details + + {expanded ? : null} +
+
+ ); +}; + export const FunctionChart: React.FC = ({ fn, chartSettings, @@ -31,15 +51,16 @@ export const FunctionChart: React.FC = ({ distributionPlotSettings, height, }) => { - if (fn.parameters.length > 1) { + console.log(fn.parameters().length); + if (fn.parameters().length !== 1) { return ( Only functions with one parameter are displayed. ); } - const result1 = runForeign(fn, [chartSettings.start], environment); - const result2 = runForeign(fn, [chartSettings.stop], environment); + const result1 = fn.call([chartSettings.start]); + const result2 = fn.call([chartSettings.stop]); const getValidResult = () => { if (result1.tag === "Ok") { return result1; @@ -52,15 +73,11 @@ export const FunctionChart: React.FC = ({ const validResult = getValidResult(); if (validResult.tag === "Error") { - return ( - - {errorValueToString(validResult.value)} - - ); + return ; } switch (validResult.value.tag) { - case "distribution": + case SqValueTag.Distribution: return ( = ({ distributionPlotSettings={distributionPlotSettings} /> ); - case "number": + case SqValueTag.Number: return ( ; -type point = { x: number; value: result }; +type point = { x: number; value: result }; -let getPercentiles = ({ chartSettings, fn, environment }) => { +let getPercentiles = ({ + chartSettings, + fn, + environment, +}: { + chartSettings: FunctionChartSettings; + fn: SqLambda; + environment: environment; +}) => { let chartPointsToRender = _rangeByCount( chartSettings.start, chartSettings.stop, @@ -87,9 +94,9 @@ let getPercentiles = ({ chartSettings, fn, environment }) => { ); let chartPointsData: point[] = chartPointsToRender.map((x) => { - let result = runForeign(fn, [x], environment); + let result = fn.call([x]); if (result.tag === "Ok") { - if (result.value.tag === "distribution") { + if (result.value.tag === SqValueTag.Distribution) { return { x, value: { tag: "Ok", value: result.value.value } }; } else { return { @@ -104,13 +111,13 @@ let getPercentiles = ({ chartSettings, fn, environment }) => { } else { return { x, - value: { tag: "Error", value: errorValueToString(result.value) }, + value: { tag: "Error", value: result.value.toString() }, }; } }); let initialPartition: [ - { x: number; value: Distribution }[], + { x: number; value: SqDistribution }[], { x: number; value: string }[] ] = [[], []]; @@ -126,26 +133,23 @@ let getPercentiles = ({ chartSettings, fn, environment }) => { let groupedErrors: errors = _.groupBy(errors, (x) => x.value); let percentiles: percentiles = functionImage.map(({ x, value }) => { - // We convert it to to a pointSet distribution first, so that in case its a sample set - // distribution, it doesn't internally convert it to a pointSet distribution for every - // single inv() call. - let toPointSet: Distribution = unwrap(value.toPointSet()); - return { + const res = { x: x, - p1: unwrap(toPointSet.inv(0.01)), - p5: unwrap(toPointSet.inv(0.05)), - p10: unwrap(toPointSet.inv(0.1)), - p20: unwrap(toPointSet.inv(0.2)), - p30: unwrap(toPointSet.inv(0.3)), - p40: unwrap(toPointSet.inv(0.4)), - p50: unwrap(toPointSet.inv(0.5)), - p60: unwrap(toPointSet.inv(0.6)), - p70: unwrap(toPointSet.inv(0.7)), - p80: unwrap(toPointSet.inv(0.8)), - p90: unwrap(toPointSet.inv(0.9)), - p95: unwrap(toPointSet.inv(0.95)), - p99: unwrap(toPointSet.inv(0.99)), + 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 }; @@ -168,19 +172,20 @@ export const FunctionChart1Dist: React.FC = ({ const signalListeners = { mousemove: handleHover, mouseout: handleOut }; //TODO: This custom error handling is a bit hacky and should be improved. - let mouseItem: result = !!mouseOverlay - ? runForeign(fn, [mouseOverlay], environment) + let mouseItem: result = !!mouseOverlay + ? fn.call([mouseOverlay]) : { tag: "Error", - value: { - tag: "RETodo", - value: "Hover x-coordinate returned NaN. Expected a number.", - }, + value: SqError.createOtherError( + "Hover x-coordinate returned NaN. Expected a number." + ), }; let showChart = - mouseItem.tag === "Ok" && mouseItem.value.tag === "distribution" ? ( + mouseItem.tag === "Ok" && + mouseItem.value.tag === SqValueTag.Distribution ? ( }; -let getFunctionImage = ({ chartSettings, fn, environment }) => { +let getFunctionImage = ({ + chartSettings, + fn, + environment, +}: { + chartSettings: FunctionChartSettings; + fn: SqLambda; + environment: environment; +}) => { let chartPointsToRender = _rangeByCount( chartSettings.start, chartSettings.stop, @@ -46,9 +49,9 @@ let getFunctionImage = ({ chartSettings, fn, environment }) => { ); let chartPointsData: point[] = chartPointsToRender.map((x) => { - let result = runForeign(fn, [x], environment); + let result = fn.call([x]); if (result.tag === "Ok") { - if (result.value.tag == "number") { + if (result.value.tag === SqValueTag.Number) { return { x, value: { tag: "Ok", value: result.value.value } }; } else { return { @@ -62,7 +65,7 @@ let getFunctionImage = ({ chartSettings, fn, environment }) => { } else { return { x, - value: { tag: "Error", value: errorValueToString(result.value) }, + value: { tag: "Error", value: result.value.toString() }, }; } }); diff --git a/packages/components/src/components/SquiggleChart.tsx b/packages/components/src/components/SquiggleChart.tsx index 00688512..215031a7 100644 --- a/packages/components/src/components/SquiggleChart.tsx +++ b/packages/components/src/components/SquiggleChart.tsx @@ -1,25 +1,17 @@ import * as React from "react"; -import { - squiggleExpression, - bindings, - environment, - jsImports, - defaultImports, - defaultBindings, - defaultEnvironment, -} from "@quri/squiggle-lang"; +import { SqValue, environment, SqProject } from "@quri/squiggle-lang"; import { useSquiggle } from "../lib/hooks"; import { SquiggleViewer } from "./SquiggleViewer"; +import { JsImports } from "../lib/jsImports"; +import { getValueToRender } from "../lib/utility"; -export interface SquiggleChartProps { +export type SquiggleChartProps = { /** The input string for squiggle */ - code?: string; + code: string; /** Allows to re-run the code if code hasn't changed */ executionId?: number; /** If the output requires monte carlo sampling, the amount of samples */ sampleCount?: number; - /** The amount of points returned to draw the distribution */ - environment?: environment; /** If the result is a function, where the function domain starts */ diagramStart?: number; /** If the result is a function, where the function domain ends */ @@ -27,14 +19,12 @@ export interface SquiggleChartProps { /** If the result is a function, the amount of stops sampled */ diagramCount?: number; /** When the squiggle code gets reevaluated */ - onChange?(expr: squiggleExpression | undefined): void; + onChange?(expr: SqValue | undefined, sourceName: string): void; /** CSS width of the element */ width?: number; height?: number; - /** Bindings of previous variables declared */ - bindings?: bindings; /** JS imported parameters */ - jsImports?: jsImports; + jsImports?: JsImports; /** Whether to show a summary of the distribution */ showSummary?: boolean; /** Set the x scale to be logarithmic by deault */ @@ -51,24 +41,36 @@ export interface SquiggleChartProps { minX?: number; /** Specify the upper bound of the x scale */ maxX?: number; + /** Whether the x-axis should be dates or numbers */ + xAxisType?: "number" | "dateTime"; /** Whether to show vega actions to the user, so they can copy the chart spec */ distributionChartActions?: boolean; enableLocalSettings?: boolean; -} +} & (StandaloneExecutionProps | ProjectExecutionProps); +// Props needed for a standalone execution +type StandaloneExecutionProps = { + project?: undefined; + continues?: undefined; + /** The amount of points returned to draw the distribution, not needed if using a project */ + environment?: environment; +}; + +// Props needed when executing inside a project. +type ProjectExecutionProps = { + environment?: undefined; + /** The project that this execution is part of */ + project: SqProject; + /** What other squiggle sources from the project to continue. Default [] */ + continues?: string[]; +}; const defaultOnChange = () => {}; +const defaultImports: JsImports = {}; +const defaultContinues: string[] = []; -export const SquiggleChart: React.FC = React.memo( - ({ - code = "", - executionId = 0, - environment, - onChange = defaultOnChange, // defaultOnChange must be constant, don't move its definition here - height = 200, - bindings = defaultBindings, - jsImports = defaultImports, +export const splitSquiggleChartSettings = (props: SquiggleChartProps) => { + const { showSummary = false, - width, logX = false, expY = false, diagramStart = 0, @@ -79,44 +81,79 @@ export const SquiggleChart: React.FC = React.memo( maxX, color, title, + xAxisType = "number", distributionChartActions, - enableLocalSettings = false, - }) => { - const result = useSquiggle({ + } = props; + + const distributionPlotSettings = { + showSummary, + logX, + expY, + format: tickFormat, + minX, + maxX, + color, + title, + xAxisType, + actions: distributionChartActions, + }; + + const chartSettings = { + start: diagramStart, + stop: diagramStop, + count: diagramCount, + }; + + return { distributionPlotSettings, chartSettings }; +}; + +export const SquiggleChart: React.FC = React.memo( + (props) => { + const { distributionPlotSettings, chartSettings } = + splitSquiggleChartSettings(props); + + const { + code, + jsImports = defaultImports, + onChange = defaultOnChange, // defaultOnChange must be constant, don't move its definition here + executionId = 0, + width, + height = 200, + enableLocalSettings = false, + continues = defaultContinues, + } = props; + + const p = React.useMemo(() => { + if (props.project) { + return props.project; + } else { + const p = SqProject.create(); + if (props.environment) { + p.setEnvironment(props.environment); + } + return p; + } + }, [props.project, props.environment]); + + const resultAndBindings = useSquiggle({ + continues, + project: p, code, - bindings, - environment, jsImports, onChange, executionId, }); - const distributionPlotSettings = { - showSummary, - logX, - expY, - format: tickFormat, - minX, - maxX, - color, - title, - actions: distributionChartActions, - }; - - const chartSettings = { - start: diagramStart, - stop: diagramStop, - count: diagramCount, - }; + const valueToRender = getValueToRender(resultAndBindings); return ( ); diff --git a/packages/components/src/components/SquiggleEditor.tsx b/packages/components/src/components/SquiggleEditor.tsx index 027eecb9..38caa04d 100644 --- a/packages/components/src/components/SquiggleEditor.tsx +++ b/packages/components/src/components/SquiggleEditor.tsx @@ -1,23 +1,29 @@ import React from "react"; import { CodeEditor } from "./CodeEditor"; -import { environment, bindings, jsImports } from "@quri/squiggle-lang"; -import { defaultImports, defaultBindings } from "@quri/squiggle-lang"; import { SquiggleContainer } from "./SquiggleContainer"; -import { SquiggleChart, SquiggleChartProps } from "./SquiggleChart"; -import { useSquigglePartial, useMaybeControlledValue } from "../lib/hooks"; -import { SquiggleErrorAlert } from "./SquiggleErrorAlert"; +import { + splitSquiggleChartSettings, + SquiggleChartProps, +} from "./SquiggleChart"; +import { useMaybeControlledValue, useSquiggle } from "../lib/hooks"; +import { JsImports } from "../lib/jsImports"; +import { defaultEnvironment, SqLocation, SqProject } from "@quri/squiggle-lang"; +import { SquiggleViewer } from "./SquiggleViewer"; +import { getErrorLocations, getValueToRender } from "../lib/utility"; const WrappedCodeEditor: React.FC<{ code: string; setCode: (code: string) => void; -}> = ({ code, setCode }) => ( -
+ errorLocations?: SqLocation[]; +}> = ({ code, setCode, errorLocations }) => ( +
); @@ -27,6 +33,9 @@ export type SquiggleEditorProps = SquiggleChartProps & { onCodeChange?: (code: string) => void; }; +const defaultOnChange = () => {}; +const defaultImports: JsImports = {}; + export const SquiggleEditor: React.FC = (props) => { const [code, setCode] = useMaybeControlledValue({ value: props.code, @@ -34,59 +43,54 @@ export const SquiggleEditor: React.FC = (props) => { onChange: props.onCodeChange, }); - let chartProps = { ...props, code }; - return ( - - - - - ); -}; + const { distributionPlotSettings, chartSettings } = + splitSquiggleChartSettings(props); -export interface SquigglePartialProps { - /** The text inside the input (controlled) */ - code?: string; - /** The default text inside the input (unControlled) */ - defaultCode?: string; - /** when the environment changes. Used again for notebook magic*/ - onChange?(expr: bindings | undefined): void; - /** When the code changes */ - onCodeChange?(code: string): void; - /** Previously declared variables */ - bindings?: bindings; - /** If the output requires monte carlo sampling, the amount of samples */ - environment?: environment; - /** Variables imported from js */ - jsImports?: jsImports; -} - -export const SquigglePartial: React.FC = ({ - code: controlledCode, - defaultCode = "", - onChange, - onCodeChange, - bindings = defaultBindings, - environment, - jsImports = defaultImports, -}: SquigglePartialProps) => { - const [code, setCode] = useMaybeControlledValue({ - value: controlledCode, - defaultValue: defaultCode, - onChange: onCodeChange, - }); - - const result = useSquigglePartial({ - code, - bindings, + const { environment, + jsImports = defaultImports, + onChange = defaultOnChange, // defaultOnChange must be constant, don't move its definition here + executionId = 0, + width, + height = 200, + enableLocalSettings = false, + } = props; + + const project = React.useMemo(() => { + const p = SqProject.create(); + if (environment) { + p.setEnvironment(environment); + } + return p; + }, [environment]); + + const resultAndBindings = useSquiggle({ + code, + project, jsImports, onChange, + executionId, }); + const valueToRender = getValueToRender(resultAndBindings); + const errorLocations = getErrorLocations(resultAndBindings.result); + return ( - - {result.tag !== "Ok" ? : null} + + ); }; diff --git a/packages/components/src/components/SquiggleEditorWithImportedBindings.tsx b/packages/components/src/components/SquiggleEditorWithImportedBindings.tsx deleted file mode 100644 index 5dcc3241..00000000 --- a/packages/components/src/components/SquiggleEditorWithImportedBindings.tsx +++ /dev/null @@ -1,52 +0,0 @@ -import React from "react"; -import { SquiggleEditor } from "./SquiggleEditor"; -import type { SquiggleEditorProps } from "./SquiggleEditor"; -import { runPartial, defaultBindings } from "@quri/squiggle-lang"; -import type { - result, - errorValue, - bindings as bindingsType, -} from "@quri/squiggle-lang"; - -function resultDefault(x: result): bindingsType { - switch (x.tag) { - case "Ok": - return x.value; - case "Error": - return defaultBindings; - } -} - -export type SquiggleEditorWithImportedBindingsProps = SquiggleEditorProps & { - bindingsImportUrl: string; -}; - -export const SquiggleEditorWithImportedBindings: React.FC< - SquiggleEditorWithImportedBindingsProps -> = (props) => { - const { bindingsImportUrl, ...editorProps } = props; - const [bindingsResult, setBindingsResult] = React.useState({ - tag: "Ok", - value: defaultBindings, - } as result); - React.useEffect(() => { - async function retrieveBindings(fileName: string) { - let contents = await fetch(fileName).then((response) => { - return response.text(); - }); - setBindingsResult( - runPartial( - contents, - editorProps.bindings, - editorProps.environment, - editorProps.jsImports - ) - ); - } - retrieveBindings(bindingsImportUrl); - }, [bindingsImportUrl]); - const deliveredBindings = resultDefault(bindingsResult); - return ( - - ); -}; diff --git a/packages/components/src/components/SquiggleErrorAlert.tsx b/packages/components/src/components/SquiggleErrorAlert.tsx index 31d7e352..fee0fca5 100644 --- a/packages/components/src/components/SquiggleErrorAlert.tsx +++ b/packages/components/src/components/SquiggleErrorAlert.tsx @@ -1,11 +1,44 @@ -import { errorValue, errorValueToString } from "@quri/squiggle-lang"; +import { SqError, SqFrame } from "@quri/squiggle-lang"; import React from "react"; import { ErrorAlert } from "./Alert"; type Props = { - error: errorValue; + error: SqError; +}; + +const StackTraceFrame: React.FC<{ frame: SqFrame }> = ({ frame }) => { + const location = frame.location(); + return ( +
+ {frame.name()} + {location + ? ` at line ${location.start.line}, column ${location.start.column}` + : ""} +
+ ); +}; + +const StackTrace: React.FC = ({ error }) => { + const frames = error.getFrameArray(); + return frames.length ? ( +
+
Stack trace:
+
+ {frames.map((frame, i) => ( + + ))} +
+
+ ) : null; }; export const SquiggleErrorAlert: React.FC = ({ error }) => { - return {errorValueToString(error)}; + return ( + +
+
{error.toString()}
+ +
+
+ ); }; diff --git a/packages/components/src/components/SquigglePlayground.tsx b/packages/components/src/components/SquigglePlayground.tsx index c3e38b1a..9a778297 100644 --- a/packages/components/src/components/SquigglePlayground.tsx +++ b/packages/components/src/components/SquigglePlayground.tsx @@ -8,7 +8,11 @@ import React, { } from "react"; import { useForm, UseFormRegister, useWatch } from "react-hook-form"; import * as yup from "yup"; -import { useMaybeControlledValue, useRunnerState } from "../lib/hooks"; +import { + useMaybeControlledValue, + useRunnerState, + useSquiggle, +} from "../lib/hooks"; import { yupResolver } from "@hookform/resolvers/yup"; import { ChartSquareBarIcon, @@ -24,9 +28,9 @@ import { } from "@heroicons/react/solid"; import clsx from "clsx"; -import { defaultBindings, environment } from "@quri/squiggle-lang"; +import { environment, SqProject } from "@quri/squiggle-lang"; -import { SquiggleChart, SquiggleChartProps } from "./SquiggleChart"; +import { SquiggleChartProps } from "./SquiggleChart"; import { CodeEditor } from "./CodeEditor"; import { JsonEditor } from "./JsonEditor"; import { ErrorAlert, SuccessAlert } from "./Alert"; @@ -39,6 +43,9 @@ import { ViewSettings, viewSettingsSchema } from "./ViewSettings"; import { HeadedSection } from "./ui/HeadedSection"; import { defaultTickFormat } from "../lib/distributionSpecBuilder"; import { Button } from "./ui/Button"; +import { JsImports } from "../lib/jsImports"; +import { getErrorLocations, getValueToRender } from "../lib/utility"; +import { SquiggleViewer } from "./SquiggleViewer"; type PlaygroundProps = SquiggleChartProps & { /** The initial squiggle string to put in the playground */ @@ -112,8 +119,8 @@ const SamplingSettings: React.FC<{ register: UseFormRegister }> = ({ ); const InputVariablesSettings: React.FC<{ - initialImports: any; // TODO - any json type - setImports: (imports: any) => void; + initialImports: JsImports; + setImports: (imports: JsImports) => void; }> = ({ initialImports, setImports }) => { const [importString, setImportString] = useState(() => JSON.stringify(initialImports) @@ -122,7 +129,7 @@ const InputVariablesSettings: React.FC<{ const onChange = (value: string) => { setImportString(value); - let imports = {} as any; + let imports = {}; try { imports = JSON.parse(value); setImportsAreValid(true); @@ -175,7 +182,7 @@ const RunControls: React.FC<{ const CurrentPlayIcon = isRunning ? RefreshIcon : PlayIcon; return ( -
+
{autorunMode ? null : (