fix export and prepare for cli lib (#325)
* add a test Signed-off-by: Jess Frazelle <github@jessfraz.com> * fixes Signed-off-by: Jess Frazelle <github@jessfraz.com> * fix Signed-off-by: Jess Frazelle <github@jessfraz.com> * fixup and make cleaner cfg options Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * fixes Signed-off-by: Jess Frazelle <github@jessfraz.com> * redo Signed-off-by: Jess Frazelle <github@jessfraz.com> * rearrange Signed-off-by: Jess Frazelle <github@jessfraz.com> * fixes Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * bincode error Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * working Signed-off-by: Jess Frazelle <github@jessfraz.com> * switch to bson Signed-off-by: Jess Frazelle <github@jessfraz.com> * remove all bincode Signed-off-by: Jess Frazelle <github@jessfraz.com> * fix clippy Signed-off-by: Jess Frazelle <github@jessfraz.com> --------- Signed-off-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
		
							
								
								
									
										2
									
								
								.github/workflows/cargo-build.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								.github/workflows/cargo-build.yml
									
									
									
									
										vendored
									
									
								
							@ -43,7 +43,5 @@ jobs:
 | 
			
		||||
      - name: Run cargo build
 | 
			
		||||
        run: |
 | 
			
		||||
          cd "${{ matrix.dir }}"
 | 
			
		||||
          cargo build --all --no-default-features --features noweb
 | 
			
		||||
          cargo build --all --no-default-features --features web
 | 
			
		||||
          cargo build --all
 | 
			
		||||
        shell: bash
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										5
									
								
								.github/workflows/cargo-test.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								.github/workflows/cargo-test.yml
									
									
									
									
										vendored
									
									
								
							@ -45,4 +45,7 @@ jobs:
 | 
			
		||||
        shell: bash
 | 
			
		||||
        run: |-
 | 
			
		||||
          cd "${{ matrix.dir }}"
 | 
			
		||||
          cargo llvm-cov nextest --lcov --output-path lcov.info --test-threads=1 --no-fail-fast
 | 
			
		||||
          cargo test --all
 | 
			
		||||
        env:
 | 
			
		||||
          KITTYCAD_API_TOKEN: ${{secrets.KITTYCAD_API_TOKEN}}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -25,5 +25,6 @@ yarn-error.log*
 | 
			
		||||
# rust
 | 
			
		||||
src/wasm-lib/target
 | 
			
		||||
src/wasm-lib/bindings
 | 
			
		||||
src/wasm-lib/kcl/bindings
 | 
			
		||||
public/wasm_lib_bg.wasm
 | 
			
		||||
src/wasm-lib/lcov.info
 | 
			
		||||
 | 
			
		||||
@ -60,9 +60,9 @@
 | 
			
		||||
    "simpleserver": "http-server ./public --cors -p 3000",
 | 
			
		||||
    "fmt": "prettier --write ./src",
 | 
			
		||||
    "fmt-check": "prettier --check ./src",
 | 
			
		||||
    "build:wasm": "yarn wasm-prep && (cd src/wasm-lib && wasm-pack build --target web --out-dir pkg --no-default-features --features web && cargo test --all) && cp src/wasm-lib/pkg/wasm_lib_bg.wasm public && yarn fmt && yarn remove-importmeta",
 | 
			
		||||
    "build:wasm": "yarn wasm-prep && (cd src/wasm-lib && wasm-pack build --target web --out-dir pkg && cargo test --all) && cp src/wasm-lib/pkg/wasm_lib_bg.wasm public && yarn fmt && yarn remove-importmeta",
 | 
			
		||||
    "remove-importmeta": "sed -i 's/import.meta.url//g' \"./src/wasm-lib/pkg/wasm_lib.js\"; sed -i '' 's/import.meta.url//g' \"./src/wasm-lib/pkg/wasm_lib.js\" || echo \"sed for both mac and linux\"",
 | 
			
		||||
    "wasm-prep": "rm -rf src/wasm-lib/pkg && mkdir src/wasm-lib/pkg && rm -rf src/wasm-lib/bindings",
 | 
			
		||||
    "wasm-prep": "rm -rf src/wasm-lib/pkg && mkdir src/wasm-lib/pkg && rm -rf src/wasm-lib/kcl/bindings",
 | 
			
		||||
    "lint": "eslint --fix src",
 | 
			
		||||
    "bump-jsons": "echo \"$(jq --arg v \"$VERSION\" '.version=$v' package.json --indent 2)\" > package.json && echo \"$(jq --arg v \"$VERSION\" '.package.version=$v' src-tauri/tauri.conf.json --indent 2)\" > src-tauri/tauri.conf.json"
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,7 @@ import { parse_js } from '../wasm-lib/pkg/wasm_lib'
 | 
			
		||||
import { initPromise } from './rust'
 | 
			
		||||
import { Token } from './tokeniser'
 | 
			
		||||
import { KCLError } from './errors'
 | 
			
		||||
import { KclError as RustKclError } from '../wasm-lib/bindings/KclError'
 | 
			
		||||
import { KclError as RustKclError } from '../wasm-lib/kcl/bindings/KclError'
 | 
			
		||||
 | 
			
		||||
export const rangeTypeFix = (ranges: number[][]): [number, number][] =>
 | 
			
		||||
  ranges.map(([start, end]) => [start, end])
 | 
			
		||||
 | 
			
		||||
@ -1,20 +1,20 @@
 | 
			
		||||
export type { Program } from '../wasm-lib/bindings/Program'
 | 
			
		||||
export type { Value } from '../wasm-lib/bindings/Value'
 | 
			
		||||
export type { ObjectExpression } from '../wasm-lib/bindings/ObjectExpression'
 | 
			
		||||
export type { MemberExpression } from '../wasm-lib/bindings/MemberExpression'
 | 
			
		||||
export type { PipeExpression } from '../wasm-lib/bindings/PipeExpression'
 | 
			
		||||
export type { VariableDeclaration } from '../wasm-lib/bindings/VariableDeclaration'
 | 
			
		||||
export type { PipeSubstitution } from '../wasm-lib/bindings/PipeSubstitution'
 | 
			
		||||
export type { Identifier } from '../wasm-lib/bindings/Identifier'
 | 
			
		||||
export type { UnaryExpression } from '../wasm-lib/bindings/UnaryExpression'
 | 
			
		||||
export type { BinaryExpression } from '../wasm-lib/bindings/BinaryExpression'
 | 
			
		||||
export type { ReturnStatement } from '../wasm-lib/bindings/ReturnStatement'
 | 
			
		||||
export type { ExpressionStatement } from '../wasm-lib/bindings/ExpressionStatement'
 | 
			
		||||
export type { CallExpression } from '../wasm-lib/bindings/CallExpression'
 | 
			
		||||
export type { VariableDeclarator } from '../wasm-lib/bindings/VariableDeclarator'
 | 
			
		||||
export type { BinaryPart } from '../wasm-lib/bindings/BinaryPart'
 | 
			
		||||
export type { Literal } from '../wasm-lib/bindings/Literal'
 | 
			
		||||
export type { ArrayExpression } from '../wasm-lib/bindings/ArrayExpression'
 | 
			
		||||
export type { Program } from '../wasm-lib/kcl/bindings/Program'
 | 
			
		||||
export type { Value } from '../wasm-lib/kcl/bindings/Value'
 | 
			
		||||
export type { ObjectExpression } from '../wasm-lib/kcl/bindings/ObjectExpression'
 | 
			
		||||
export type { MemberExpression } from '../wasm-lib/kcl/bindings/MemberExpression'
 | 
			
		||||
export type { PipeExpression } from '../wasm-lib/kcl/bindings/PipeExpression'
 | 
			
		||||
export type { VariableDeclaration } from '../wasm-lib/kcl/bindings/VariableDeclaration'
 | 
			
		||||
export type { PipeSubstitution } from '../wasm-lib/kcl/bindings/PipeSubstitution'
 | 
			
		||||
export type { Identifier } from '../wasm-lib/kcl/bindings/Identifier'
 | 
			
		||||
export type { UnaryExpression } from '../wasm-lib/kcl/bindings/UnaryExpression'
 | 
			
		||||
export type { BinaryExpression } from '../wasm-lib/kcl/bindings/BinaryExpression'
 | 
			
		||||
export type { ReturnStatement } from '../wasm-lib/kcl/bindings/ReturnStatement'
 | 
			
		||||
export type { ExpressionStatement } from '../wasm-lib/kcl/bindings/ExpressionStatement'
 | 
			
		||||
export type { CallExpression } from '../wasm-lib/kcl/bindings/CallExpression'
 | 
			
		||||
export type { VariableDeclarator } from '../wasm-lib/kcl/bindings/VariableDeclarator'
 | 
			
		||||
export type { BinaryPart } from '../wasm-lib/kcl/bindings/BinaryPart'
 | 
			
		||||
export type { Literal } from '../wasm-lib/kcl/bindings/Literal'
 | 
			
		||||
export type { ArrayExpression } from '../wasm-lib/kcl/bindings/ArrayExpression'
 | 
			
		||||
 | 
			
		||||
export type SyntaxType =
 | 
			
		||||
  | 'Program'
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
import { Diagnostic } from '@codemirror/lint'
 | 
			
		||||
import { KclError as RustKclError } from '../wasm-lib/bindings/KclError'
 | 
			
		||||
import { KclError as RustKclError } from '../wasm-lib/kcl/bindings/KclError'
 | 
			
		||||
 | 
			
		||||
type ExtractKind<T> = T extends { kind: infer K } ? K : never
 | 
			
		||||
export class KCLError {
 | 
			
		||||
 | 
			
		||||
@ -4,10 +4,10 @@ import {
 | 
			
		||||
  ArtifactMap,
 | 
			
		||||
  SourceRangeMap,
 | 
			
		||||
} from './std/engineConnection'
 | 
			
		||||
import { ProgramReturn } from '../wasm-lib/bindings/ProgramReturn'
 | 
			
		||||
import { ProgramReturn } from '../wasm-lib/kcl/bindings/ProgramReturn'
 | 
			
		||||
import { execute_wasm } from '../wasm-lib/pkg/wasm_lib'
 | 
			
		||||
import { KCLError } from './errors'
 | 
			
		||||
import { KclError as RustKclError } from '../wasm-lib/bindings/KclError'
 | 
			
		||||
import { KclError as RustKclError } from '../wasm-lib/kcl/bindings/KclError'
 | 
			
		||||
import { rangeTypeFix } from './abstractSyntaxTree'
 | 
			
		||||
 | 
			
		||||
export type SourceRange = [number, number]
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
import { lexer_js } from '../wasm-lib/pkg/wasm_lib'
 | 
			
		||||
import { initPromise } from './rust'
 | 
			
		||||
import { Token } from '../wasm-lib/bindings/Token'
 | 
			
		||||
import { Token } from '../wasm-lib/kcl/bindings/Token'
 | 
			
		||||
 | 
			
		||||
export type { Token } from '../wasm-lib/bindings/Token'
 | 
			
		||||
export type { Token } from '../wasm-lib/kcl/bindings/Token'
 | 
			
		||||
 | 
			
		||||
export async function asyncLexer(str: string): Promise<Token[]> {
 | 
			
		||||
  await initPromise
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										263
									
								
								src/wasm-lib/Cargo.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										263
									
								
								src/wasm-lib/Cargo.lock
									
									
									
										generated
									
									
									
								
							@ -27,6 +27,17 @@ version = "1.0.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "ahash"
 | 
			
		||||
version = "0.7.6"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "getrandom",
 | 
			
		||||
 "once_cell",
 | 
			
		||||
 "version_check",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "aho-corasick"
 | 
			
		||||
version = "1.0.4"
 | 
			
		||||
@ -109,6 +120,12 @@ dependencies = [
 | 
			
		||||
 "rustc-demangle",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "base64"
 | 
			
		||||
version = "0.13.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "base64"
 | 
			
		||||
version = "0.21.2"
 | 
			
		||||
@ -147,6 +164,18 @@ version = "2.4.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "bitvec"
 | 
			
		||||
version = "1.0.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "funty",
 | 
			
		||||
 "radium",
 | 
			
		||||
 "tap",
 | 
			
		||||
 "wyz",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "block-buffer"
 | 
			
		||||
version = "0.10.4"
 | 
			
		||||
@ -156,6 +185,28 @@ dependencies = [
 | 
			
		||||
 "generic-array",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "bson"
 | 
			
		||||
version = "2.6.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "9aeb8bae494e49dbc330dd23cf78f6f7accee22f640ce3ab17841badaa4ce232"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "ahash",
 | 
			
		||||
 "base64 0.13.1",
 | 
			
		||||
 "bitvec",
 | 
			
		||||
 "chrono",
 | 
			
		||||
 "hex",
 | 
			
		||||
 "indexmap 1.9.3",
 | 
			
		||||
 "js-sys",
 | 
			
		||||
 "lazy_static",
 | 
			
		||||
 "rand",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "serde_bytes",
 | 
			
		||||
 "serde_json",
 | 
			
		||||
 "time 0.3.27",
 | 
			
		||||
 "uuid",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "bumpalo"
 | 
			
		||||
version = "3.13.0"
 | 
			
		||||
@ -281,6 +332,16 @@ dependencies = [
 | 
			
		||||
 "unicode-segmentation",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "core-foundation"
 | 
			
		||||
version = "0.9.3"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "core-foundation-sys",
 | 
			
		||||
 "libc",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "core-foundation-sys"
 | 
			
		||||
version = "0.8.4"
 | 
			
		||||
@ -488,6 +549,12 @@ dependencies = [
 | 
			
		||||
 "unicode-segmentation",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "funty"
 | 
			
		||||
version = "2.0.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "futures"
 | 
			
		||||
version = "0.3.28"
 | 
			
		||||
@ -606,28 +673,6 @@ version = "0.28.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "gloo-events"
 | 
			
		||||
version = "0.2.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "27c26fb45f7c385ba980f5fa87ac677e363949e065a083722697ef1b2cc91e41"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "wasm-bindgen",
 | 
			
		||||
 "web-sys",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "gloo-file"
 | 
			
		||||
version = "0.3.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "97563d71863fb2824b2e974e754a81d19c4a7ec47b09ced8a0e6656b6d54bd1f"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "gloo-events",
 | 
			
		||||
 "js-sys",
 | 
			
		||||
 "wasm-bindgen",
 | 
			
		||||
 "web-sys",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "gloo-utils"
 | 
			
		||||
version = "0.2.0"
 | 
			
		||||
@ -693,6 +738,12 @@ version = "0.3.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "hex"
 | 
			
		||||
version = "0.4.3"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "home"
 | 
			
		||||
version = "0.5.5"
 | 
			
		||||
@ -881,13 +932,41 @@ dependencies = [
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "kittycad"
 | 
			
		||||
version = "0.2.19"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "0443a9f76cee80d5a43d076028d3ce39d2f6f6b66fc5c1a0ce24f8d7caf733b9"
 | 
			
		||||
name = "kcl"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "anyhow",
 | 
			
		||||
 "base64",
 | 
			
		||||
 "bson",
 | 
			
		||||
 "derive-docs",
 | 
			
		||||
 "expectorate",
 | 
			
		||||
 "futures",
 | 
			
		||||
 "js-sys",
 | 
			
		||||
 "kittycad",
 | 
			
		||||
 "lazy_static",
 | 
			
		||||
 "parse-display",
 | 
			
		||||
 "pretty_assertions",
 | 
			
		||||
 "regex",
 | 
			
		||||
 "reqwest",
 | 
			
		||||
 "schemars",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "serde_json",
 | 
			
		||||
 "thiserror",
 | 
			
		||||
 "tokio",
 | 
			
		||||
 "tokio-tungstenite",
 | 
			
		||||
 "ts-rs",
 | 
			
		||||
 "uuid",
 | 
			
		||||
 "wasm-bindgen",
 | 
			
		||||
 "wasm-bindgen-futures",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "kittycad"
 | 
			
		||||
version = "0.2.20"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "e71916b50966110cb9f70aa6c310748a153fdcb0183a02615324a6f457fd18e8"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "anyhow",
 | 
			
		||||
 "base64 0.21.2",
 | 
			
		||||
 "bytes",
 | 
			
		||||
 "chrono",
 | 
			
		||||
 "data-encoding",
 | 
			
		||||
@ -1151,6 +1230,12 @@ dependencies = [
 | 
			
		||||
 "serde_json",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "openssl-probe"
 | 
			
		||||
version = "0.1.5"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "os_str_bytes"
 | 
			
		||||
version = "6.5.1"
 | 
			
		||||
@ -1244,9 +1329,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "pin-project-lite"
 | 
			
		||||
version = "0.2.12"
 | 
			
		||||
version = "0.2.13"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05"
 | 
			
		||||
checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "pin-utils"
 | 
			
		||||
@ -1321,6 +1406,12 @@ dependencies = [
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "radium"
 | 
			
		||||
version = "0.7.0"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "rand"
 | 
			
		||||
version = "0.8.5"
 | 
			
		||||
@ -1433,7 +1524,7 @@ version = "0.11.20"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "base64",
 | 
			
		||||
 "base64 0.21.2",
 | 
			
		||||
 "bytes",
 | 
			
		||||
 "encoding_rs",
 | 
			
		||||
 "futures-core",
 | 
			
		||||
@ -1519,9 +1610,9 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "rustix"
 | 
			
		||||
version = "0.38.8"
 | 
			
		||||
version = "0.38.9"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f"
 | 
			
		||||
checksum = "9bfe0f2582b4931a45d1fa608f8a8722e8b3c7ac54dd6d5f3b3212791fedef49"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "bitflags 2.4.0",
 | 
			
		||||
 "errno",
 | 
			
		||||
@ -1542,13 +1633,25 @@ dependencies = [
 | 
			
		||||
 "sct",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "rustls-native-certs"
 | 
			
		||||
version = "0.6.3"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "openssl-probe",
 | 
			
		||||
 "rustls-pemfile",
 | 
			
		||||
 "schannel",
 | 
			
		||||
 "security-framework",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "rustls-pemfile"
 | 
			
		||||
version = "1.0.3"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "base64",
 | 
			
		||||
 "base64 0.21.2",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
@ -1582,6 +1685,15 @@ dependencies = [
 | 
			
		||||
 "winapi-util",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "schannel"
 | 
			
		||||
version = "0.1.22"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "windows-sys 0.48.0",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "schemars"
 | 
			
		||||
version = "0.8.12"
 | 
			
		||||
@ -1627,6 +1739,29 @@ dependencies = [
 | 
			
		||||
 "untrusted",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "security-framework"
 | 
			
		||||
version = "2.9.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "bitflags 1.3.2",
 | 
			
		||||
 "core-foundation",
 | 
			
		||||
 "core-foundation-sys",
 | 
			
		||||
 "libc",
 | 
			
		||||
 "security-framework-sys",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "security-framework-sys"
 | 
			
		||||
version = "2.9.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "core-foundation-sys",
 | 
			
		||||
 "libc",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "semver"
 | 
			
		||||
version = "0.11.0"
 | 
			
		||||
@ -1647,18 +1782,27 @@ dependencies = [
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "serde"
 | 
			
		||||
version = "1.0.186"
 | 
			
		||||
version = "1.0.187"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "9f5db24220c009de9bd45e69fb2938f4b6d2df856aa9304ce377b3180f83b7c1"
 | 
			
		||||
checksum = "30a7fe14252655bd1e578af19f5fa00fe02fd0013b100ca6b49fde31c41bae4c"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "serde_derive",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "serde_derive"
 | 
			
		||||
version = "1.0.186"
 | 
			
		||||
name = "serde_bytes"
 | 
			
		||||
version = "0.11.12"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "5ad697f7e0b65af4983a4ce8f56ed5b357e8d3c36651bf6a7e13639c17b8e670"
 | 
			
		||||
checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "serde",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "serde_derive"
 | 
			
		||||
version = "1.0.187"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "e46b2a6ca578b3f1d4501b12f78ed4692006d79d82a1a7c561c12dbc3d625eb8"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "proc-macro2",
 | 
			
		||||
 "quote",
 | 
			
		||||
@ -1682,6 +1826,7 @@ version = "1.0.105"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "indexmap 2.0.0",
 | 
			
		||||
 "itoa",
 | 
			
		||||
 "ryu",
 | 
			
		||||
 "serde",
 | 
			
		||||
@ -1925,6 +2070,12 @@ version = "0.2.2"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "f764005d11ee5f36500a149ace24e00e3da98b0158b3e2d53a7495660d3f4d60"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "tap"
 | 
			
		||||
version = "1.0.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "task-local-extensions"
 | 
			
		||||
version = "0.1.4"
 | 
			
		||||
@ -2110,7 +2261,10 @@ checksum = "2b2dbec703c26b00d74844519606ef15d09a7d6857860f84ad223dec002ddea2"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "futures-util",
 | 
			
		||||
 "log",
 | 
			
		||||
 "rustls",
 | 
			
		||||
 "rustls-native-certs",
 | 
			
		||||
 "tokio",
 | 
			
		||||
 "tokio-rustls",
 | 
			
		||||
 "tungstenite",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -2227,6 +2381,7 @@ dependencies = [
 | 
			
		||||
 "httparse",
 | 
			
		||||
 "log",
 | 
			
		||||
 "rand",
 | 
			
		||||
 "rustls",
 | 
			
		||||
 "sha1",
 | 
			
		||||
 "thiserror",
 | 
			
		||||
 "url",
 | 
			
		||||
@ -2435,30 +2590,11 @@ checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
 | 
			
		||||
name = "wasm-lib"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "anyhow",
 | 
			
		||||
 "backtrace",
 | 
			
		||||
 "bincode",
 | 
			
		||||
 "derive-docs",
 | 
			
		||||
 "expectorate",
 | 
			
		||||
 "futures",
 | 
			
		||||
 "gloo-file",
 | 
			
		||||
 "bson",
 | 
			
		||||
 "gloo-utils",
 | 
			
		||||
 "http",
 | 
			
		||||
 "httparse",
 | 
			
		||||
 "js-sys",
 | 
			
		||||
 "kcl",
 | 
			
		||||
 "kittycad",
 | 
			
		||||
 "lazy_static",
 | 
			
		||||
 "parse-display",
 | 
			
		||||
 "pretty_assertions",
 | 
			
		||||
 "regex",
 | 
			
		||||
 "schemars",
 | 
			
		||||
 "serde",
 | 
			
		||||
 "serde_json",
 | 
			
		||||
 "thiserror",
 | 
			
		||||
 "tokio",
 | 
			
		||||
 "tokio-tungstenite",
 | 
			
		||||
 "ts-rs",
 | 
			
		||||
 "uuid",
 | 
			
		||||
 "wasm-bindgen",
 | 
			
		||||
 "wasm-bindgen-futures",
 | 
			
		||||
]
 | 
			
		||||
@ -2661,6 +2797,15 @@ dependencies = [
 | 
			
		||||
 "windows-sys 0.48.0",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "wyz"
 | 
			
		||||
version = "0.5.1"
 | 
			
		||||
source = "registry+https://github.com/rust-lang/crates.io-index"
 | 
			
		||||
checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed"
 | 
			
		||||
dependencies = [
 | 
			
		||||
 "tap",
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
[[package]]
 | 
			
		||||
name = "yaml-rust"
 | 
			
		||||
version = "0.4.5"
 | 
			
		||||
 | 
			
		||||
@ -8,28 +8,11 @@ edition = "2021"
 | 
			
		||||
crate-type = ["cdylib"]
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
anyhow = "1.0.75"
 | 
			
		||||
backtrace = "0.3"
 | 
			
		||||
bincode = "1.3.3"
 | 
			
		||||
derive-docs = { path = "derive-docs" }
 | 
			
		||||
futures = { version = "0.3.28", optional = true }
 | 
			
		||||
gloo-file = { version = "0.3.0", optional = true }
 | 
			
		||||
bson = { version = "2.6.1", features = ["uuid-1", "chrono"] }
 | 
			
		||||
gloo-utils = "0.2.0"
 | 
			
		||||
http = "0.2.9"
 | 
			
		||||
httparse = { version = "1.8.0", optional = true }
 | 
			
		||||
js-sys = { version = "0.3.64", optional = true }
 | 
			
		||||
kcl = { path = "kcl" }
 | 
			
		||||
kittycad = { version = "0.2.15", default-features = false, features = ["js"] }
 | 
			
		||||
lazy_static = "1.4.0"
 | 
			
		||||
parse-display = "0.8.2"
 | 
			
		||||
regex = "1.7.1"
 | 
			
		||||
schemars = { version = "0.8", features = ["url", "uuid1"] }
 | 
			
		||||
serde = {version = "1.0.152", features = ["derive"] }
 | 
			
		||||
serde_json = "1.0.93"
 | 
			
		||||
thiserror = "1.0.47"
 | 
			
		||||
tokio = { version = "1.32.0", features = ["full"], optional = true }
 | 
			
		||||
tokio-tungstenite = { version = "0.20.0", optional = true }
 | 
			
		||||
ts-rs = { git = "https://github.com/kittycad/ts-rs.git", branch = "serde_json", features = ["serde-json-impl", "uuid-impl"] }
 | 
			
		||||
uuid = { version = "1.4.1", features = ["v4", "js", "serde"] }
 | 
			
		||||
wasm-bindgen = "0.2.87"
 | 
			
		||||
wasm-bindgen-futures = "0.4.37"
 | 
			
		||||
 | 
			
		||||
@ -37,17 +20,8 @@ wasm-bindgen-futures = "0.4.37"
 | 
			
		||||
panic = "abort"
 | 
			
		||||
debug = true
 | 
			
		||||
 | 
			
		||||
[dev-dependencies]
 | 
			
		||||
expectorate = "1.0.7"
 | 
			
		||||
pretty_assertions = "1.4.0"
 | 
			
		||||
tokio = { version = "1.32.0", features = ["rt-multi-thread", "macros", "time"] }
 | 
			
		||||
 | 
			
		||||
[features]
 | 
			
		||||
default = ["web"]
 | 
			
		||||
web = ["dep:gloo-file", "dep:js-sys"]
 | 
			
		||||
noweb = ["dep:futures", "dep:httparse", "dep:tokio", "dep:tokio-tungstenite"]
 | 
			
		||||
 | 
			
		||||
[workspace]
 | 
			
		||||
members = [
 | 
			
		||||
	"derive-docs"
 | 
			
		||||
	"derive-docs",
 | 
			
		||||
	"kcl"
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										42
									
								
								src/wasm-lib/kcl/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/wasm-lib/kcl/Cargo.toml
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,42 @@
 | 
			
		||||
[package]
 | 
			
		||||
name = "kcl"
 | 
			
		||||
description = "KittyCAD Language"
 | 
			
		||||
version = "0.1.0"
 | 
			
		||||
edition = "2021"
 | 
			
		||||
 | 
			
		||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
anyhow = "1.0.75"
 | 
			
		||||
derive-docs = { path = "../derive-docs" }
 | 
			
		||||
kittycad = { version = "0.2.15", default-features = false, features = ["js"] }
 | 
			
		||||
lazy_static = "1.4.0"
 | 
			
		||||
parse-display = "0.8.2"
 | 
			
		||||
regex = "1.7.1"
 | 
			
		||||
schemars = { version = "0.8", features = ["url", "uuid1"] }
 | 
			
		||||
serde = {version = "1.0.152", features = ["derive"] }
 | 
			
		||||
serde_json = "1.0.93"
 | 
			
		||||
thiserror = "1.0.47"
 | 
			
		||||
ts-rs = { git = "https://github.com/kittycad/ts-rs.git", branch = "serde_json", features = ["serde-json-impl", "uuid-impl"] }
 | 
			
		||||
uuid = { version = "1.4.1", features = ["v4", "js", "serde"] }
 | 
			
		||||
wasm-bindgen = "0.2.87"
 | 
			
		||||
wasm-bindgen-futures = "0.4.37"
 | 
			
		||||
 | 
			
		||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
 | 
			
		||||
js-sys = { version = "0.3.64" }
 | 
			
		||||
 | 
			
		||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
 | 
			
		||||
bson = { version = "2.6.1", features = ["uuid-1", "chrono"] }
 | 
			
		||||
futures = { version = "0.3.28" }
 | 
			
		||||
reqwest = { version = "0.11.20", default-features = false }
 | 
			
		||||
tokio = { version = "1.32.0", features = ["full"] }
 | 
			
		||||
tokio-tungstenite = { version = "0.20.0", features = ["rustls-tls-native-roots"] }
 | 
			
		||||
 | 
			
		||||
[profile.release]
 | 
			
		||||
panic = "abort"
 | 
			
		||||
debug = true
 | 
			
		||||
 | 
			
		||||
[dev-dependencies]
 | 
			
		||||
expectorate = "1.0.7"
 | 
			
		||||
pretty_assertions = "1.4.0"
 | 
			
		||||
tokio = { version = "1.32.0", features = ["rt-multi-thread", "macros", "time"] }
 | 
			
		||||
							
								
								
									
										211
									
								
								src/wasm-lib/kcl/src/engine/conn.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										211
									
								
								src/wasm-lib/kcl/src/engine/conn.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,211 @@
 | 
			
		||||
//! Functions for setting up our WebSocket and WebRTC connections for communications with the
 | 
			
		||||
//! engine.
 | 
			
		||||
 | 
			
		||||
use std::sync::Arc;
 | 
			
		||||
 | 
			
		||||
use anyhow::Result;
 | 
			
		||||
use futures::{SinkExt, StreamExt};
 | 
			
		||||
use kittycad::types::{OkWebSocketResponseData, WebSocketRequest, WebSocketResponse};
 | 
			
		||||
use tokio_tungstenite::tungstenite::Message as WsMsg;
 | 
			
		||||
 | 
			
		||||
use crate::errors::{KclError, KclErrorDetails};
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub struct EngineConnection {
 | 
			
		||||
    tcp_write:
 | 
			
		||||
        futures::stream::SplitSink<tokio_tungstenite::WebSocketStream<reqwest::Upgraded>, WsMsg>,
 | 
			
		||||
    tcp_read_handle: tokio::task::JoinHandle<Result<()>>,
 | 
			
		||||
    export_notifier: Arc<tokio::sync::Notify>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Drop for EngineConnection {
 | 
			
		||||
    fn drop(&mut self) {
 | 
			
		||||
        // Drop the read handle.
 | 
			
		||||
        self.tcp_read_handle.abort();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct TcpRead {
 | 
			
		||||
    stream: futures::stream::SplitStream<tokio_tungstenite::WebSocketStream<reqwest::Upgraded>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl TcpRead {
 | 
			
		||||
    pub async fn read(&mut self) -> Result<WebSocketResponse> {
 | 
			
		||||
        let msg = self.stream.next().await.unwrap()?;
 | 
			
		||||
        let msg: WebSocketResponse = match msg {
 | 
			
		||||
            WsMsg::Text(text) => serde_json::from_str(&text)?,
 | 
			
		||||
            WsMsg::Binary(bin) => bson::from_slice(&bin)?,
 | 
			
		||||
            other => anyhow::bail!("Unexpected websocket message from server: {}", other),
 | 
			
		||||
        };
 | 
			
		||||
        Ok(msg)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl EngineConnection {
 | 
			
		||||
    pub async fn new(ws: reqwest::Upgraded, export_dir: &str) -> Result<EngineConnection> {
 | 
			
		||||
        // Make sure the export directory exists and that it is a directory.
 | 
			
		||||
        let export_dir = std::path::Path::new(export_dir).to_owned();
 | 
			
		||||
        if !export_dir.exists() {
 | 
			
		||||
            anyhow::bail!("Export directory does not exist: {}", export_dir.display());
 | 
			
		||||
        }
 | 
			
		||||
        // Make sure it is a directory.
 | 
			
		||||
        if !export_dir.is_dir() {
 | 
			
		||||
            anyhow::bail!(
 | 
			
		||||
                "Export directory is not a directory: {}",
 | 
			
		||||
                export_dir.display()
 | 
			
		||||
            );
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let ws_stream = tokio_tungstenite::WebSocketStream::from_raw_socket(
 | 
			
		||||
            ws,
 | 
			
		||||
            tokio_tungstenite::tungstenite::protocol::Role::Client,
 | 
			
		||||
            None,
 | 
			
		||||
        )
 | 
			
		||||
        .await;
 | 
			
		||||
 | 
			
		||||
        let (tcp_write, tcp_read) = ws_stream.split();
 | 
			
		||||
 | 
			
		||||
        let mut tcp_read = TcpRead { stream: tcp_read };
 | 
			
		||||
 | 
			
		||||
        let export_notifier = Arc::new(tokio::sync::Notify::new());
 | 
			
		||||
        let export_notifier_clone = export_notifier.clone();
 | 
			
		||||
 | 
			
		||||
        let tcp_read_handle = tokio::spawn(async move {
 | 
			
		||||
            // Get Websocket messages from API server
 | 
			
		||||
            loop {
 | 
			
		||||
                match tcp_read.read().await {
 | 
			
		||||
                    Ok(ws_resp) => {
 | 
			
		||||
                        if !ws_resp.success {
 | 
			
		||||
                            println!("got ws errors: {:?}", ws_resp.errors);
 | 
			
		||||
                            export_notifier.notify_one();
 | 
			
		||||
                            continue;
 | 
			
		||||
                        }
 | 
			
		||||
 | 
			
		||||
                        if let Some(msg) = ws_resp.resp {
 | 
			
		||||
                            match msg {
 | 
			
		||||
                                OkWebSocketResponseData::IceServerInfo { ice_servers } => {
 | 
			
		||||
                                    println!("got ice server info: {:?}", ice_servers);
 | 
			
		||||
                                }
 | 
			
		||||
                                OkWebSocketResponseData::SdpAnswer { answer } => {
 | 
			
		||||
                                    println!("got sdp answer: {:?}", answer);
 | 
			
		||||
                                }
 | 
			
		||||
                                OkWebSocketResponseData::TrickleIce { candidate } => {
 | 
			
		||||
                                    println!("got trickle ice: {:?}", candidate);
 | 
			
		||||
                                }
 | 
			
		||||
                                OkWebSocketResponseData::Modeling { .. } => {}
 | 
			
		||||
                                OkWebSocketResponseData::Export { files } => {
 | 
			
		||||
                                    // Save the files to our export directory.
 | 
			
		||||
                                    for file in files {
 | 
			
		||||
                                        let path = export_dir.join(file.name);
 | 
			
		||||
                                        std::fs::write(&path, file.contents)?;
 | 
			
		||||
                                        println!("Wrote file: {}", path.display());
 | 
			
		||||
                                    }
 | 
			
		||||
 | 
			
		||||
                                    // Tell the export notifier that we have new files.
 | 
			
		||||
                                    export_notifier.notify_one();
 | 
			
		||||
                                }
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    Err(e) => {
 | 
			
		||||
                        println!("got ws error: {:?}", e);
 | 
			
		||||
                        export_notifier.notify_one();
 | 
			
		||||
                        continue;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        Ok(EngineConnection {
 | 
			
		||||
            tcp_write,
 | 
			
		||||
            tcp_read_handle,
 | 
			
		||||
            export_notifier: export_notifier_clone,
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn wait_for_files(&self) {
 | 
			
		||||
        self.export_notifier.notified().await;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn tcp_send(&mut self, msg: WebSocketRequest) -> Result<()> {
 | 
			
		||||
        let msg = serde_json::to_string(&msg)?;
 | 
			
		||||
        self.tcp_write.send(WsMsg::Text(msg)).await?;
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn send_modeling_cmd(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        id: uuid::Uuid,
 | 
			
		||||
        source_range: crate::executor::SourceRange,
 | 
			
		||||
        cmd: kittycad::types::ModelingCmd,
 | 
			
		||||
    ) -> Result<(), KclError> {
 | 
			
		||||
        futures::executor::block_on(
 | 
			
		||||
            self.tcp_send(WebSocketRequest::ModelingCmdReq { cmd, cmd_id: id }),
 | 
			
		||||
        )
 | 
			
		||||
        .map_err(|e| {
 | 
			
		||||
            KclError::Engine(KclErrorDetails {
 | 
			
		||||
                message: format!("Failed to send modeling command: {}", e),
 | 
			
		||||
                source_ranges: vec![source_range],
 | 
			
		||||
            })
 | 
			
		||||
        })?;
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use crate::executor::{execute, BodyType, ProgramMemory, SourceRange};
 | 
			
		||||
 | 
			
		||||
    pub async fn parse_execute_export(code: &str) -> Result<()> {
 | 
			
		||||
        let tokens = crate::tokeniser::lexer(code);
 | 
			
		||||
        let export_dir_str = "/tmp/";
 | 
			
		||||
        let program = crate::parser::abstract_syntax_tree(&tokens)?;
 | 
			
		||||
        let mut mem: ProgramMemory = Default::default();
 | 
			
		||||
        let mut engine = EngineConnection::new(
 | 
			
		||||
            "wss://api.dev.kittycad.io/ws/modeling/commands?webrtc=false",
 | 
			
		||||
            std::env::var("KITTYCAD_API_TOKEN").unwrap().as_str(),
 | 
			
		||||
            "modeling-app-tests",
 | 
			
		||||
            export_dir_str,
 | 
			
		||||
        )
 | 
			
		||||
        .await?;
 | 
			
		||||
        let _ = execute(program, &mut mem, BodyType::Root, &mut engine)?;
 | 
			
		||||
        // Send an export request to the engine.
 | 
			
		||||
        engine.send_modeling_cmd(
 | 
			
		||||
            uuid::Uuid::new_v4(),
 | 
			
		||||
            SourceRange::default(),
 | 
			
		||||
            kittycad::types::ModelingCmd::Export {
 | 
			
		||||
                entity_ids: vec![],
 | 
			
		||||
                format: kittycad::types::OutputFormat::Gltf {
 | 
			
		||||
                    presentation: kittycad::types::Presentation::Pretty,
 | 
			
		||||
                    storage: kittycad::types::Storage::Embedded,
 | 
			
		||||
                },
 | 
			
		||||
            },
 | 
			
		||||
        )?;
 | 
			
		||||
 | 
			
		||||
        engine.wait_for_files().await;
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[tokio::test(flavor = "multi_thread")]
 | 
			
		||||
    async fn test_export_file() {
 | 
			
		||||
        let ast = r#"const part001 = startSketchAt([-0.01, -0.06])
 | 
			
		||||
  |> line([0, 20], %)
 | 
			
		||||
  |> line([5, 0], %)
 | 
			
		||||
  |> line([-10, 5], %)
 | 
			
		||||
  |> close(%)
 | 
			
		||||
  |> extrude(4, %)
 | 
			
		||||
 | 
			
		||||
show(part001)"#;
 | 
			
		||||
        parse_execute_export(ast).await.unwrap();
 | 
			
		||||
 | 
			
		||||
        // Ensure we have a file called "part001.gltf" in the export directory.
 | 
			
		||||
        let export_dir = std::path::Path::new("/tmp/");
 | 
			
		||||
        let export_file = export_dir.join("part001.gltf");
 | 
			
		||||
        assert!(export_file.exists());
 | 
			
		||||
        // Make sure the file is not empty.
 | 
			
		||||
        assert!(export_file.metadata().unwrap().len() != 0);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -9,11 +9,7 @@ use crate::errors::KclError;
 | 
			
		||||
pub struct EngineConnection {}
 | 
			
		||||
 | 
			
		||||
impl EngineConnection {
 | 
			
		||||
    pub async fn new(
 | 
			
		||||
        _conn_str: &str,
 | 
			
		||||
        _auth_token: &str,
 | 
			
		||||
        _origin: &str,
 | 
			
		||||
    ) -> Result<EngineConnection> {
 | 
			
		||||
    pub async fn new() -> Result<EngineConnection> {
 | 
			
		||||
        Ok(EngineConnection {})
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,7 @@ use wasm_bindgen::prelude::*;
 | 
			
		||||
 | 
			
		||||
use crate::errors::{KclError, KclErrorDetails};
 | 
			
		||||
 | 
			
		||||
#[wasm_bindgen(module = "/../lang/std/engineConnection.ts")]
 | 
			
		||||
#[wasm_bindgen(module = "/../../lang/std/engineConnection.ts")]
 | 
			
		||||
extern "C" {
 | 
			
		||||
    #[derive(Debug, Clone)]
 | 
			
		||||
    pub type EngineCommandManager;
 | 
			
		||||
@ -2,19 +2,19 @@
 | 
			
		||||
 | 
			
		||||
use wasm_bindgen::prelude::*;
 | 
			
		||||
 | 
			
		||||
#[cfg(feature = "noweb")]
 | 
			
		||||
#[cfg(not(target_arch = "wasm32"))]
 | 
			
		||||
#[cfg(not(test))]
 | 
			
		||||
pub mod conn_noweb;
 | 
			
		||||
#[cfg(feature = "noweb")]
 | 
			
		||||
pub mod conn;
 | 
			
		||||
#[cfg(not(target_arch = "wasm32"))]
 | 
			
		||||
#[cfg(not(test))]
 | 
			
		||||
pub use conn_noweb::EngineConnection;
 | 
			
		||||
pub use conn::EngineConnection;
 | 
			
		||||
 | 
			
		||||
#[cfg(feature = "web")]
 | 
			
		||||
#[cfg(target_arch = "wasm32")]
 | 
			
		||||
#[cfg(not(test))]
 | 
			
		||||
pub mod conn_web;
 | 
			
		||||
#[cfg(feature = "web")]
 | 
			
		||||
pub mod conn_wasm;
 | 
			
		||||
#[cfg(target_arch = "wasm32")]
 | 
			
		||||
#[cfg(not(test))]
 | 
			
		||||
pub use conn_web::EngineConnection;
 | 
			
		||||
pub use conn_wasm::EngineConnection;
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
pub mod conn_mock;
 | 
			
		||||
@ -31,27 +31,16 @@ pub struct EngineManager {
 | 
			
		||||
 | 
			
		||||
#[wasm_bindgen]
 | 
			
		||||
impl EngineManager {
 | 
			
		||||
    #[cfg(feature = "web")]
 | 
			
		||||
    #[cfg(target_arch = "wasm32")]
 | 
			
		||||
    #[cfg(not(test))]
 | 
			
		||||
    #[wasm_bindgen(constructor)]
 | 
			
		||||
    pub async fn new(manager: conn_web::EngineCommandManager) -> EngineManager {
 | 
			
		||||
    pub async fn new(manager: conn_wasm::EngineCommandManager) -> EngineManager {
 | 
			
		||||
        EngineManager {
 | 
			
		||||
            // This unwrap is safe because the connection is always created.
 | 
			
		||||
            connection: EngineConnection::new(manager).await.unwrap(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[cfg(not(feature = "web"))]
 | 
			
		||||
    #[wasm_bindgen(constructor)]
 | 
			
		||||
    pub async fn new(conn_str: &str, auth_token: &str, origin: &str) -> EngineManager {
 | 
			
		||||
        EngineManager {
 | 
			
		||||
            // TODO: fix unwrap.
 | 
			
		||||
            connection: EngineConnection::new(conn_str, auth_token, origin)
 | 
			
		||||
                .await
 | 
			
		||||
                .unwrap(),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn send_modeling_cmd(&mut self, id_str: &str, cmd_str: &str) -> Result<(), String> {
 | 
			
		||||
        let id = uuid::Uuid::parse_str(id_str).map_err(|e| e.to_string())?;
 | 
			
		||||
        let cmd = serde_json::from_str(cmd_str).map_err(|e| e.to_string())?;
 | 
			
		||||
@ -6,9 +6,6 @@ use anyhow::Result;
 | 
			
		||||
use schemars::JsonSchema;
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
 | 
			
		||||
#[cfg(not(test))]
 | 
			
		||||
use wasm_bindgen::prelude::*;
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    abstract_syntax_tree_types::{BodyItem, FunctionExpression, Value},
 | 
			
		||||
    engine::EngineConnection,
 | 
			
		||||
@ -506,7 +503,7 @@ impl Default for PipeInfo {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Execute a AST's program.
 | 
			
		||||
fn execute(
 | 
			
		||||
pub fn execute(
 | 
			
		||||
    program: crate::abstract_syntax_tree_types::Program,
 | 
			
		||||
    memory: &mut ProgramMemory,
 | 
			
		||||
    options: BodyType,
 | 
			
		||||
@ -681,53 +678,6 @@ fn execute(
 | 
			
		||||
    Ok(memory.clone())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// wasm_bindgen wrapper for execute
 | 
			
		||||
#[cfg(feature = "web")]
 | 
			
		||||
#[cfg(not(test))]
 | 
			
		||||
#[wasm_bindgen]
 | 
			
		||||
pub async fn execute_wasm(
 | 
			
		||||
    program_str: &str,
 | 
			
		||||
    memory_str: &str,
 | 
			
		||||
    manager: crate::engine::conn_web::EngineCommandManager,
 | 
			
		||||
) -> Result<JsValue, String> {
 | 
			
		||||
    use gloo_utils::format::JsValueSerdeExt;
 | 
			
		||||
 | 
			
		||||
    // deserialize the ast from a stringified json
 | 
			
		||||
    let program: crate::abstract_syntax_tree_types::Program =
 | 
			
		||||
        serde_json::from_str(program_str).map_err(|e| e.to_string())?;
 | 
			
		||||
    let mut mem: ProgramMemory = serde_json::from_str(memory_str).map_err(|e| e.to_string())?;
 | 
			
		||||
 | 
			
		||||
    let mut engine = EngineConnection::new(manager)
 | 
			
		||||
        .await
 | 
			
		||||
        .map_err(|e| format!("{:?}", e))?;
 | 
			
		||||
 | 
			
		||||
    let memory = execute(program, &mut mem, BodyType::Root, &mut engine).map_err(String::from)?;
 | 
			
		||||
    // The serde-wasm-bindgen does not work here because of weird HashMap issues so we use the
 | 
			
		||||
    // gloo-serialize crate instead.
 | 
			
		||||
    JsValue::from_serde(&memory).map_err(|e| e.to_string())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// wasm_bindgen wrapper for execute
 | 
			
		||||
#[cfg(not(feature = "web"))]
 | 
			
		||||
#[wasm_bindgen]
 | 
			
		||||
pub async fn execute_wasm(program_str: &str, memory_str: &str) -> Result<JsValue, String> {
 | 
			
		||||
    use gloo_utils::format::JsValueSerdeExt;
 | 
			
		||||
 | 
			
		||||
    // deserialize the ast from a stringified json
 | 
			
		||||
    let program: crate::abstract_syntax_tree_types::Program =
 | 
			
		||||
        serde_json::from_str(program_str).map_err(|e| e.to_string())?;
 | 
			
		||||
    let mut mem: ProgramMemory = serde_json::from_str(memory_str).map_err(|e| e.to_string())?;
 | 
			
		||||
 | 
			
		||||
    let mut engine = EngineConnection::new("dev.kittycad.io", "some-token", "")
 | 
			
		||||
        .await
 | 
			
		||||
        .map_err(|e| format!("{:?}", e))?;
 | 
			
		||||
 | 
			
		||||
    let memory = execute(program, &mut mem, BodyType::Root, &mut engine).map_err(String::from)?;
 | 
			
		||||
    // The serde-wasm-bindgen does not work here because of weird HashMap issues so we use the
 | 
			
		||||
    // gloo-serialize crate instead.
 | 
			
		||||
    JsValue::from_serde(&memory).map_err(|e| e.to_string())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use super::*;
 | 
			
		||||
@ -737,7 +687,7 @@ mod tests {
 | 
			
		||||
        let tokens = crate::tokeniser::lexer(code);
 | 
			
		||||
        let program = crate::parser::abstract_syntax_tree(&tokens)?;
 | 
			
		||||
        let mut mem: ProgramMemory = Default::default();
 | 
			
		||||
        let mut engine = EngineConnection::new("dev.kittycad.io", "some-token", "").await?;
 | 
			
		||||
        let mut engine = EngineConnection::new().await?;
 | 
			
		||||
        let memory = execute(program, &mut mem, BodyType::Root, &mut engine)?;
 | 
			
		||||
 | 
			
		||||
        Ok(memory)
 | 
			
		||||
							
								
								
									
										10
									
								
								src/wasm-lib/kcl/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								src/wasm-lib/kcl/src/lib.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,10 @@
 | 
			
		||||
pub mod abstract_syntax_tree_types;
 | 
			
		||||
mod docs;
 | 
			
		||||
pub mod engine;
 | 
			
		||||
pub mod errors;
 | 
			
		||||
pub mod executor;
 | 
			
		||||
pub mod math_parser;
 | 
			
		||||
pub mod parser;
 | 
			
		||||
pub mod recast;
 | 
			
		||||
pub mod std;
 | 
			
		||||
pub mod tokeniser;
 | 
			
		||||
@ -9,12 +9,8 @@ use crate::abstract_syntax_tree_types::{
 | 
			
		||||
};
 | 
			
		||||
use crate::errors::{KclError, KclErrorDetails};
 | 
			
		||||
use crate::math_parser::parse_expression;
 | 
			
		||||
use crate::tokeniser::lexer;
 | 
			
		||||
use crate::tokeniser::{Token, TokenType};
 | 
			
		||||
 | 
			
		||||
use gloo_utils::format::JsValueSerdeExt;
 | 
			
		||||
use wasm_bindgen::prelude::*;
 | 
			
		||||
 | 
			
		||||
fn make_identifier(tokens: &[Token], index: usize) -> Identifier {
 | 
			
		||||
    let current_token = &tokens[index];
 | 
			
		||||
    Identifier {
 | 
			
		||||
@ -1540,15 +1536,6 @@ pub fn abstract_syntax_tree(tokens: &[Token]) -> Result<Program, KclError> {
 | 
			
		||||
    })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[wasm_bindgen]
 | 
			
		||||
pub fn parse_js(js: &str) -> Result<JsValue, String> {
 | 
			
		||||
    let tokens = lexer(js);
 | 
			
		||||
    let program = abstract_syntax_tree(&tokens).map_err(String::from)?;
 | 
			
		||||
    // The serde-wasm-bindgen does not work here because of weird HashMap issues so we use the
 | 
			
		||||
    // gloo-serialize crate instead.
 | 
			
		||||
    JsValue::from_serde(&program).map_err(|e| e.to_string())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use super::*;
 | 
			
		||||
@ -1556,7 +1543,7 @@ mod tests {
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_make_identifier() {
 | 
			
		||||
        let tokens = lexer("a");
 | 
			
		||||
        let tokens = crate::tokeniser::lexer("a");
 | 
			
		||||
        let identifier = make_identifier(&tokens, 0);
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            Identifier {
 | 
			
		||||
@ -1570,7 +1557,7 @@ mod tests {
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_make_identifier_with_const_myvar_equals_5_and_index_2() {
 | 
			
		||||
        let tokens = lexer("const myVar = 5");
 | 
			
		||||
        let tokens = crate::tokeniser::lexer("const myVar = 5");
 | 
			
		||||
        let identifier = make_identifier(&tokens, 2);
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            Identifier {
 | 
			
		||||
@ -1584,7 +1571,7 @@ mod tests {
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_make_identifier_multiline() {
 | 
			
		||||
        let tokens = lexer("const myVar = 5\nconst newVar = myVar + 1");
 | 
			
		||||
        let tokens = crate::tokeniser::lexer("const myVar = 5\nconst newVar = myVar + 1");
 | 
			
		||||
        let identifier = make_identifier(&tokens, 2);
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            Identifier {
 | 
			
		||||
@ -1607,7 +1594,7 @@ mod tests {
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_make_identifier_call_expression() {
 | 
			
		||||
        let tokens = lexer("log(5, \"hello\", aIdentifier)");
 | 
			
		||||
        let tokens = crate::tokeniser::lexer("log(5, \"hello\", aIdentifier)");
 | 
			
		||||
        let identifier = make_identifier(&tokens, 0);
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            Identifier {
 | 
			
		||||
@ -1629,7 +1616,7 @@ mod tests {
 | 
			
		||||
    }
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_make_none_code_node() {
 | 
			
		||||
        let tokens = lexer("log(5, \"hello\", aIdentifier)");
 | 
			
		||||
        let tokens = crate::tokeniser::lexer("log(5, \"hello\", aIdentifier)");
 | 
			
		||||
        let index = 4;
 | 
			
		||||
        let expected_output = (
 | 
			
		||||
            Some(NoneCodeNode {
 | 
			
		||||
@ -1651,7 +1638,7 @@ mod tests {
 | 
			
		||||
            7,
 | 
			
		||||
        );
 | 
			
		||||
        assert_eq!(make_none_code_node(&tokens, index), expected_output);
 | 
			
		||||
        let tokens = lexer(
 | 
			
		||||
        let tokens = crate::tokeniser::lexer(
 | 
			
		||||
            r#"
 | 
			
		||||
const yo = { a: { b: { c: '123' } } }
 | 
			
		||||
// this is a comment
 | 
			
		||||
@ -1700,7 +1687,7 @@ const key = 'c'"#,
 | 
			
		||||
            31,
 | 
			
		||||
        );
 | 
			
		||||
        assert_eq!(make_none_code_node(&tokens, index), expected_output);
 | 
			
		||||
        let tokens = lexer(
 | 
			
		||||
        let tokens = crate::tokeniser::lexer(
 | 
			
		||||
            r#"const mySketch = startSketchAt([0,0])
 | 
			
		||||
  |> lineTo({ to: [0, 1], tag: 'myPath' }, %)
 | 
			
		||||
  |> lineTo([1, 1], %) /* this is
 | 
			
		||||
@ -1724,7 +1711,7 @@ const key = 'c'"#,
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_collect_object_keys() {
 | 
			
		||||
        let tokens = lexer("const prop = yo.one[\"two\"]");
 | 
			
		||||
        let tokens = crate::tokeniser::lexer("const prop = yo.one[\"two\"]");
 | 
			
		||||
        let keys_info = collect_object_keys(&tokens, 6, None).unwrap();
 | 
			
		||||
        assert_eq!(keys_info.len(), 2);
 | 
			
		||||
        let first_key = match keys_info[0].key.clone() {
 | 
			
		||||
@ -1743,7 +1730,7 @@ const key = 'c'"#,
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_make_literal_call_expression() {
 | 
			
		||||
        let tokens = lexer("log(5, \"hello\", aIdentifier)");
 | 
			
		||||
        let tokens = crate::tokeniser::lexer("log(5, \"hello\", aIdentifier)");
 | 
			
		||||
        let literal = make_literal(&tokens, 2).unwrap();
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            Literal {
 | 
			
		||||
@ -1833,7 +1820,7 @@ const key = 'c'"#,
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_next_meaningful_token() {
 | 
			
		||||
        let _offset = 1;
 | 
			
		||||
        let tokens = lexer(
 | 
			
		||||
        let tokens = crate::tokeniser::lexer(
 | 
			
		||||
            r#"const mySketch = startSketchAt([0,0])
 | 
			
		||||
  |> lineTo({ to: [0, 1], tag: 'myPath' }, %)
 | 
			
		||||
  |> lineTo([1, 1], %) /* this is
 | 
			
		||||
@ -2218,7 +2205,7 @@ const key = 'c'"#,
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_find_closing_brace() {
 | 
			
		||||
        let tokens = lexer(
 | 
			
		||||
        let tokens = crate::tokeniser::lexer(
 | 
			
		||||
            r#"const mySketch = startSketchAt([0,0])
 | 
			
		||||
|> lineTo({ to: [0, 1], tag: 'myPath' }, %)
 | 
			
		||||
|> lineTo([1, 1], %) /* this is
 | 
			
		||||
@ -2234,22 +2221,25 @@ const key = 'c'"#,
 | 
			
		||||
        assert_eq!(find_closing_brace(&tokens, 90, 0, "").unwrap(), 92);
 | 
			
		||||
 | 
			
		||||
        let basic = "( hey )";
 | 
			
		||||
        assert_eq!(find_closing_brace(&lexer(basic), 0, 0, "").unwrap(), 4);
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            find_closing_brace(&crate::tokeniser::lexer(basic), 0, 0, "").unwrap(),
 | 
			
		||||
            4
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        let handles_non_zero_index =
 | 
			
		||||
            "(indexForBracketToRightOfThisIsTwo(shouldBeFour)AndNotThisSix)";
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            find_closing_brace(&lexer(handles_non_zero_index), 2, 0, "").unwrap(),
 | 
			
		||||
            find_closing_brace(&crate::tokeniser::lexer(handles_non_zero_index), 2, 0, "").unwrap(),
 | 
			
		||||
            4
 | 
			
		||||
        );
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            find_closing_brace(&lexer(handles_non_zero_index), 0, 0, "").unwrap(),
 | 
			
		||||
            find_closing_brace(&crate::tokeniser::lexer(handles_non_zero_index), 0, 0, "").unwrap(),
 | 
			
		||||
            6
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        let handles_nested = "{a{b{c(}d]}eathou athoeu tah u} thatOneToTheLeftIsLast }";
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            find_closing_brace(&lexer(handles_nested), 0, 0, "").unwrap(),
 | 
			
		||||
            find_closing_brace(&crate::tokeniser::lexer(handles_nested), 0, 0, "").unwrap(),
 | 
			
		||||
            18
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
@ -2258,7 +2248,7 @@ const key = 'c'"#,
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_is_call_expression() {
 | 
			
		||||
        let tokens = lexer(
 | 
			
		||||
        let tokens = crate::tokeniser::lexer(
 | 
			
		||||
            r#"const mySketch = startSketchAt([0,0])
 | 
			
		||||
|> lineTo({ to: [0, 1], tag: 'myPath' }, %)
 | 
			
		||||
|> lineTo([1, 1], %) /* this is
 | 
			
		||||
@ -2278,7 +2268,7 @@ const key = 'c'"#,
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_find_next_declaration_keyword() {
 | 
			
		||||
        let tokens = lexer(
 | 
			
		||||
        let tokens = crate::tokeniser::lexer(
 | 
			
		||||
            r#"const mySketch = startSketchAt([0,0])
 | 
			
		||||
|> lineTo({ to: [0, 1], tag: 'myPath' }, %)
 | 
			
		||||
|> lineTo([1, 1], %) /* this is
 | 
			
		||||
@ -2295,7 +2285,7 @@ const key = 'c'"#,
 | 
			
		||||
            }
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        let tokens = lexer(
 | 
			
		||||
        let tokens = crate::tokeniser::lexer(
 | 
			
		||||
            r#"const myVar = 5
 | 
			
		||||
const newVar = myVar + 1
 | 
			
		||||
"#,
 | 
			
		||||
@ -2327,7 +2317,7 @@ const newVar = myVar + 1
 | 
			
		||||
  lineTo(2, 3)
 | 
			
		||||
} |> rx(45, %)
 | 
			
		||||
"#;
 | 
			
		||||
        let tokens = lexer(code);
 | 
			
		||||
        let tokens = crate::tokeniser::lexer(code);
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            has_pipe_operator(&tokens, 0, None).unwrap(),
 | 
			
		||||
            TokenReturnWithNonCode {
 | 
			
		||||
@ -2349,7 +2339,7 @@ const newVar = myVar + 1
 | 
			
		||||
  lineTo(2, 3)
 | 
			
		||||
} |> rx(45, %) |> rx(45, %)
 | 
			
		||||
"#;
 | 
			
		||||
        let tokens = lexer(code);
 | 
			
		||||
        let tokens = crate::tokeniser::lexer(code);
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            has_pipe_operator(&tokens, 0, None).unwrap(),
 | 
			
		||||
            TokenReturnWithNonCode {
 | 
			
		||||
@ -2374,7 +2364,7 @@ const newVar = myVar + 1
 | 
			
		||||
const yo = myFunc(9()
 | 
			
		||||
  |> rx(45, %)
 | 
			
		||||
"#;
 | 
			
		||||
        let tokens = lexer(code);
 | 
			
		||||
        let tokens = crate::tokeniser::lexer(code);
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            has_pipe_operator(&tokens, 0, None).unwrap(),
 | 
			
		||||
            TokenReturnWithNonCode {
 | 
			
		||||
@ -2385,7 +2375,7 @@ const yo = myFunc(9()
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        let code = "const myVar2 = 5 + 1 |> myFn(%)";
 | 
			
		||||
        let tokens = lexer(code);
 | 
			
		||||
        let tokens = crate::tokeniser::lexer(code);
 | 
			
		||||
        assert_eq!(
 | 
			
		||||
            has_pipe_operator(&tokens, 1, None).unwrap(),
 | 
			
		||||
            TokenReturnWithNonCode {
 | 
			
		||||
@ -2410,7 +2400,7 @@ const yo = myFunc(9()
 | 
			
		||||
  lineTo(1,1)
 | 
			
		||||
} |> rx(90, %)
 | 
			
		||||
show(mySk1)"#;
 | 
			
		||||
        let tokens = lexer(code);
 | 
			
		||||
        let tokens = crate::tokeniser::lexer(code);
 | 
			
		||||
        let token_with_my_path_index = tokens
 | 
			
		||||
            .iter()
 | 
			
		||||
            .position(|token| token.value == "myPath")
 | 
			
		||||
@ -2454,7 +2444,7 @@ show(mySk1)"#;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_make_member_expression() {
 | 
			
		||||
        let tokens = lexer("const prop = yo.one[\"two\"]");
 | 
			
		||||
        let tokens = crate::tokeniser::lexer("const prop = yo.one[\"two\"]");
 | 
			
		||||
        let member_expression_return = make_member_expression(&tokens, 6).unwrap();
 | 
			
		||||
        let member_expression = member_expression_return.expression;
 | 
			
		||||
        let last_index = member_expression_return.last_index;
 | 
			
		||||
@ -2495,12 +2485,12 @@ show(mySk1)"#;
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_find_end_of_binary_expression() {
 | 
			
		||||
        let code = "1 + 2 * 3\nconst yo = 5";
 | 
			
		||||
        let tokens = lexer(code);
 | 
			
		||||
        let tokens = crate::tokeniser::lexer(code);
 | 
			
		||||
        let end = find_end_of_binary_expression(&tokens, 0).unwrap();
 | 
			
		||||
        assert_eq!(tokens[end].value, "3");
 | 
			
		||||
 | 
			
		||||
        let code = "(1 + 25) / 5 - 3\nconst yo = 5";
 | 
			
		||||
        let tokens = lexer(code);
 | 
			
		||||
        let tokens = crate::tokeniser::lexer(code);
 | 
			
		||||
        let end = find_end_of_binary_expression(&tokens, 0).unwrap();
 | 
			
		||||
        assert_eq!(tokens[end].value, "3");
 | 
			
		||||
        let index_of_5 = code.find('5').unwrap();
 | 
			
		||||
@ -2508,44 +2498,44 @@ show(mySk1)"#;
 | 
			
		||||
        assert_eq!(end_starting_at_the_5, end);
 | 
			
		||||
        // whole thing wraped
 | 
			
		||||
        let code = "((1 + 2) / 5 - 3)\nconst yo = 5";
 | 
			
		||||
        let tokens = lexer(code);
 | 
			
		||||
        let tokens = crate::tokeniser::lexer(code);
 | 
			
		||||
        let end = find_end_of_binary_expression(&tokens, 0).unwrap();
 | 
			
		||||
        assert_eq!(tokens[end].end, code.find("3)").unwrap() + 2);
 | 
			
		||||
        // whole thing wraped but given index after the first brace
 | 
			
		||||
        let code = "((1 + 2) / 5 - 3)\nconst yo = 5";
 | 
			
		||||
        let tokens = lexer(code);
 | 
			
		||||
        let tokens = crate::tokeniser::lexer(code);
 | 
			
		||||
        let end = find_end_of_binary_expression(&tokens, 1).unwrap();
 | 
			
		||||
        assert_eq!(tokens[end].value, "3");
 | 
			
		||||
        // given the index of a small wrapped section i.e. `1 + 2` in ((1 + 2) / 5 - 3)'
 | 
			
		||||
        let code = "((1 + 2) / 5 - 3)\nconst yo = 5";
 | 
			
		||||
        let tokens = lexer(code);
 | 
			
		||||
        let tokens = crate::tokeniser::lexer(code);
 | 
			
		||||
        let end = find_end_of_binary_expression(&tokens, 2).unwrap();
 | 
			
		||||
        assert_eq!(tokens[end].value, "2");
 | 
			
		||||
        // lots of silly nesting
 | 
			
		||||
        let code = "(1 + 2) / (5 - (3))\nconst yo = 5";
 | 
			
		||||
        let tokens = lexer(code);
 | 
			
		||||
        let tokens = crate::tokeniser::lexer(code);
 | 
			
		||||
        let end = find_end_of_binary_expression(&tokens, 0).unwrap();
 | 
			
		||||
        assert_eq!(tokens[end].end, code.find("))").unwrap() + 2);
 | 
			
		||||
        // with pipe operator at the end
 | 
			
		||||
        let code = "(1 + 2) / (5 - (3))\n  |> fn(%)";
 | 
			
		||||
        let tokens = lexer(code);
 | 
			
		||||
        let tokens = crate::tokeniser::lexer(code);
 | 
			
		||||
        let end = find_end_of_binary_expression(&tokens, 0).unwrap();
 | 
			
		||||
        assert_eq!(tokens[end].end, code.find("))").unwrap() + 2);
 | 
			
		||||
        // with call expression at the start of binary expression
 | 
			
		||||
        let code = "yo(2) + 3\n  |> fn(%)";
 | 
			
		||||
        let tokens = lexer(code);
 | 
			
		||||
        let tokens = crate::tokeniser::lexer(code);
 | 
			
		||||
        let end = find_end_of_binary_expression(&tokens, 0).unwrap();
 | 
			
		||||
        assert_eq!(tokens[end].value, "3");
 | 
			
		||||
        // with call expression at the end of binary expression
 | 
			
		||||
        let code = "3 + yo(2)\n  |> fn(%)";
 | 
			
		||||
        let tokens = lexer(code);
 | 
			
		||||
        let tokens = crate::tokeniser::lexer(code);
 | 
			
		||||
        let _end = find_end_of_binary_expression(&tokens, 0).unwrap();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_make_array_expression() {
 | 
			
		||||
        // input_index: 6, output_index: 14, output: {"type":"ArrayExpression","start":11,"end":26,"elements":[{"type":"Literal","start":12,"end":15,"value":"1","raw":"\"1\""},{"type":"Literal","start":17,"end":18,"value":2,"raw":"2"},{"type":"Identifier","start":20,"end":25,"name":"three"}]}
 | 
			
		||||
        let tokens = lexer("const yo = [\"1\", 2, three]");
 | 
			
		||||
        let tokens = crate::tokeniser::lexer("const yo = [\"1\", 2, three]");
 | 
			
		||||
        let array_expression = make_array_expression(&tokens, 6).unwrap();
 | 
			
		||||
        let expression = array_expression.expression;
 | 
			
		||||
        assert_eq!(array_expression.last_index, 14);
 | 
			
		||||
@ -2583,7 +2573,7 @@ show(mySk1)"#;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_make_call_expression() {
 | 
			
		||||
        let tokens = lexer("foo(\"a\", a, 3)");
 | 
			
		||||
        let tokens = crate::tokeniser::lexer("foo(\"a\", a, 3)");
 | 
			
		||||
        let result = make_call_expression(&tokens, 0).unwrap();
 | 
			
		||||
        assert_eq!(result.last_index, 9);
 | 
			
		||||
        assert_eq!(result.expression.start, 0);
 | 
			
		||||
@ -2616,7 +2606,7 @@ show(mySk1)"#;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_make_variable_declaration() {
 | 
			
		||||
        let tokens = lexer(
 | 
			
		||||
        let tokens = crate::tokeniser::lexer(
 | 
			
		||||
            r#"const yo = startSketch([0, 0])
 | 
			
		||||
  |> lineTo([1, myVar], %)
 | 
			
		||||
  |> foo(myVar2, %)
 | 
			
		||||
@ -2685,7 +2675,7 @@ show(mySk1)"#;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_make_body() {
 | 
			
		||||
        let tokens = lexer("const myVar = 5");
 | 
			
		||||
        let tokens = crate::tokeniser::lexer("const myVar = 5");
 | 
			
		||||
        let body = make_body(
 | 
			
		||||
            &tokens,
 | 
			
		||||
            0,
 | 
			
		||||
@ -2702,7 +2692,7 @@ show(mySk1)"#;
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn test_abstract_syntax_tree() {
 | 
			
		||||
        let code = "5 +6";
 | 
			
		||||
        let result = abstract_syntax_tree(&lexer(code)).unwrap();
 | 
			
		||||
        let result = abstract_syntax_tree(&crate::tokeniser::lexer(code)).unwrap();
 | 
			
		||||
        let expected_result = Program {
 | 
			
		||||
            start: 0,
 | 
			
		||||
            end: 4,
 | 
			
		||||
@ -1,7 +1,5 @@
 | 
			
		||||
//! Generates source code from the AST.
 | 
			
		||||
//! The inverse of parsing (which generates an AST from the source code)
 | 
			
		||||
use gloo_utils::format::JsValueSerdeExt;
 | 
			
		||||
use wasm_bindgen::prelude::*;
 | 
			
		||||
 | 
			
		||||
use crate::abstract_syntax_tree_types::{
 | 
			
		||||
    ArrayExpression, BinaryExpression, BinaryPart, BodyItem, CallExpression, FunctionExpression,
 | 
			
		||||
@ -400,14 +398,3 @@ pub fn recast_function(expression: FunctionExpression) -> String {
 | 
			
		||||
        )
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// wasm_bindgen wrapper for recast
 | 
			
		||||
// test for this function and by extension the recaster are done in javascript land src/lang/recast.test.ts
 | 
			
		||||
#[wasm_bindgen]
 | 
			
		||||
pub fn recast_wasm(json_str: &str) -> Result<JsValue, JsError> {
 | 
			
		||||
    // deserialize the ast from a stringified json
 | 
			
		||||
    let program: Program = serde_json::from_str(json_str).map_err(JsError::from)?;
 | 
			
		||||
 | 
			
		||||
    let result = recast(&program, "", false);
 | 
			
		||||
    Ok(JsValue::from_serde(&result)?)
 | 
			
		||||
}
 | 
			
		||||
@ -1,9 +1,9 @@
 | 
			
		||||
//! Functions implemented for language execution.
 | 
			
		||||
 | 
			
		||||
mod extrude;
 | 
			
		||||
mod segment;
 | 
			
		||||
mod sketch;
 | 
			
		||||
mod utils;
 | 
			
		||||
pub mod extrude;
 | 
			
		||||
pub mod segment;
 | 
			
		||||
pub mod sketch;
 | 
			
		||||
pub mod utils;
 | 
			
		||||
 | 
			
		||||
// TODO: Something that would be nice is if we could generate docs for Kcl based on the
 | 
			
		||||
// actual stdlib functions below.
 | 
			
		||||
@ -663,7 +663,7 @@ mod tests {
 | 
			
		||||
            buf.push_str(&fn_docs);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        expectorate::assert_contents("../../docs/kcl.md", &buf);
 | 
			
		||||
        expectorate::assert_contents("../../../docs/kcl.md", &buf);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
@ -677,7 +677,7 @@ mod tests {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        expectorate::assert_contents(
 | 
			
		||||
            "../../docs/kcl.json",
 | 
			
		||||
            "../../../docs/kcl.json",
 | 
			
		||||
            &serde_json::to_string_pretty(&json_data).unwrap(),
 | 
			
		||||
        );
 | 
			
		||||
    }
 | 
			
		||||
@ -44,7 +44,7 @@ pub fn normalize_rad(angle: f64) -> f64 {
 | 
			
		||||
/// # Examples
 | 
			
		||||
///
 | 
			
		||||
/// ```
 | 
			
		||||
/// assert_eq!(delta_angle(std::f64::consts::PI/8.0, std::f64::consts::PI/4.0), std::f64::consts::PI/8.0);
 | 
			
		||||
/// assert_eq!(kcl::std::utils::delta_angle(std::f64::consts::PI/8.0, std::f64::consts::PI/4.0), std::f64::consts::PI/8.0);
 | 
			
		||||
/// ```
 | 
			
		||||
#[allow(dead_code)]
 | 
			
		||||
pub fn delta_angle(from_angle: f64, to_angle: f64) -> f64 {
 | 
			
		||||
@ -69,8 +69,8 @@ pub fn delta_angle(from_angle: f64, to_angle: f64) -> f64 {
 | 
			
		||||
/// # Examples
 | 
			
		||||
///
 | 
			
		||||
/// ```
 | 
			
		||||
/// assert_eq!(distance_between_points(&[0.0, 0.0], &[0.0, 5.0]), 5.0);
 | 
			
		||||
/// assert_eq!(distance_between_points(&[0.0, 0.0], &[3.0, 4.0]), 5.0);
 | 
			
		||||
/// assert_eq!(kcl::std::utils::distance_between_points(&[0.0, 0.0], &[0.0, 5.0]), 5.0);
 | 
			
		||||
/// assert_eq!(kcl::std::utils::distance_between_points(&[0.0, 0.0], &[3.0, 4.0]), 5.0);
 | 
			
		||||
/// ```
 | 
			
		||||
#[allow(dead_code)]
 | 
			
		||||
pub fn distance_between_points(point_a: &[f64; 2], point_b: &[f64; 2]) -> f64 {
 | 
			
		||||
@ -1,8 +1,6 @@
 | 
			
		||||
use gloo_utils::format::JsValueSerdeExt;
 | 
			
		||||
use lazy_static::lazy_static;
 | 
			
		||||
use regex::Regex;
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
use wasm_bindgen::prelude::*;
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, PartialEq, Eq, Copy, Clone, Deserialize, Serialize, ts_rs::TS)]
 | 
			
		||||
#[ts(export)]
 | 
			
		||||
@ -273,14 +271,6 @@ pub fn lexer(str: &str) -> Vec<Token> {
 | 
			
		||||
    recursively_tokenise(str, 0, Vec::new())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// wasm_bindgen wrapper for lexer
 | 
			
		||||
// test for this function and by extension lexer are done in javascript land src/lang/tokeniser.test.ts
 | 
			
		||||
#[wasm_bindgen]
 | 
			
		||||
pub fn lexer_js(str: &str) -> Result<JsValue, JsError> {
 | 
			
		||||
    let tokens = lexer(str);
 | 
			
		||||
    Ok(JsValue::from_serde(&tokens)?)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use super::*;
 | 
			
		||||
@ -1,159 +0,0 @@
 | 
			
		||||
//! Functions for setting up our WebSocket and WebRTC connections for communications with the
 | 
			
		||||
//! engine.
 | 
			
		||||
 | 
			
		||||
use anyhow::Result;
 | 
			
		||||
use futures::{SinkExt, StreamExt};
 | 
			
		||||
use kittycad::types::{OkWebSocketResponseData, WebSocketRequest, WebSocketResponse};
 | 
			
		||||
use tokio_tungstenite::tungstenite::Message as WsMsg;
 | 
			
		||||
 | 
			
		||||
use crate::errors::{KclError, KclErrorDetails};
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
pub struct EngineConnection {
 | 
			
		||||
    tcp_write: futures::stream::SplitSink<
 | 
			
		||||
        tokio_tungstenite::WebSocketStream<
 | 
			
		||||
            tokio_tungstenite::MaybeTlsStream<tokio::net::TcpStream>,
 | 
			
		||||
        >,
 | 
			
		||||
        WsMsg,
 | 
			
		||||
    >,
 | 
			
		||||
    tcp_read_handle: tokio::task::JoinHandle<()>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Drop for EngineConnection {
 | 
			
		||||
    fn drop(&mut self) {
 | 
			
		||||
        // Drop the read handle.
 | 
			
		||||
        self.tcp_read_handle.abort();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct TcpRead {
 | 
			
		||||
    stream: futures::stream::SplitStream<
 | 
			
		||||
        tokio_tungstenite::WebSocketStream<
 | 
			
		||||
            tokio_tungstenite::MaybeTlsStream<tokio::net::TcpStream>,
 | 
			
		||||
        >,
 | 
			
		||||
    >,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl TcpRead {
 | 
			
		||||
    pub async fn read(&mut self) -> Result<WebSocketResponse> {
 | 
			
		||||
        let msg = self.stream.next().await.unwrap()?;
 | 
			
		||||
        let msg = match msg {
 | 
			
		||||
            WsMsg::Text(text) => text,
 | 
			
		||||
            WsMsg::Binary(bin) => bincode::deserialize(&bin)?,
 | 
			
		||||
            other => anyhow::bail!("Unexpected websocket message from server: {}", other),
 | 
			
		||||
        };
 | 
			
		||||
        let msg = serde_json::from_str::<WebSocketResponse>(&msg)?;
 | 
			
		||||
        Ok(msg)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl EngineConnection {
 | 
			
		||||
    pub async fn new(conn_str: &str, auth_token: &str, origin: &str) -> Result<EngineConnection> {
 | 
			
		||||
        let method = http::Method::GET.to_string();
 | 
			
		||||
        let key = tokio_tungstenite::tungstenite::handshake::client::generate_key();
 | 
			
		||||
 | 
			
		||||
        // Establish a websocket connection.
 | 
			
		||||
        let (ws_stream, _) = tokio_tungstenite::connect_async(httparse::Request {
 | 
			
		||||
            method: Some(&method),
 | 
			
		||||
            path: Some(conn_str),
 | 
			
		||||
            // TODO pass in the origin from elsewhere.
 | 
			
		||||
            headers: &mut websocket_headers(auth_token, &key, origin),
 | 
			
		||||
            version: Some(1), // HTTP/1.1
 | 
			
		||||
        })
 | 
			
		||||
        .await?;
 | 
			
		||||
 | 
			
		||||
        let (tcp_write, tcp_read) = ws_stream.split();
 | 
			
		||||
 | 
			
		||||
        let mut tcp_read = TcpRead { stream: tcp_read };
 | 
			
		||||
 | 
			
		||||
        let tcp_read_handle = tokio::spawn(async move {
 | 
			
		||||
            // Get Websocket messages from API server
 | 
			
		||||
            while let Ok(ws_resp) = tcp_read.read().await {
 | 
			
		||||
                if !ws_resp.success {
 | 
			
		||||
                    println!("got ws errors: {:?}", ws_resp.errors);
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if let Some(msg) = ws_resp.resp {
 | 
			
		||||
                    match msg {
 | 
			
		||||
                        OkWebSocketResponseData::IceServerInfo { ice_servers } => {
 | 
			
		||||
                            println!("got ice server info: {:?}", ice_servers);
 | 
			
		||||
                        }
 | 
			
		||||
                        OkWebSocketResponseData::SdpAnswer { answer } => {
 | 
			
		||||
                            println!("got sdp answer: {:?}", answer);
 | 
			
		||||
                        }
 | 
			
		||||
                        OkWebSocketResponseData::TrickleIce { candidate } => {
 | 
			
		||||
                            println!("got trickle ice: {:?}", candidate);
 | 
			
		||||
                        }
 | 
			
		||||
                        OkWebSocketResponseData::Modeling { .. } => {}
 | 
			
		||||
                        OkWebSocketResponseData::Export { .. } => {}
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        Ok(EngineConnection {
 | 
			
		||||
            tcp_write,
 | 
			
		||||
            tcp_read_handle,
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn tcp_send(&mut self, msg: WebSocketRequest) -> Result<()> {
 | 
			
		||||
        let msg = serde_json::to_string(&msg)?;
 | 
			
		||||
        self.tcp_write.send(WsMsg::Text(msg)).await?;
 | 
			
		||||
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn send_modeling_cmd(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        id: uuid::Uuid,
 | 
			
		||||
        source_range: crate::executor::SourceRange,
 | 
			
		||||
        cmd: kittycad::types::ModelingCmd,
 | 
			
		||||
    ) -> Result<(), KclError> {
 | 
			
		||||
        futures::executor::block_on(
 | 
			
		||||
            self.tcp_send(WebSocketRequest::ModelingCmdReq { cmd, cmd_id: id }),
 | 
			
		||||
        )
 | 
			
		||||
        .map_err(|e| {
 | 
			
		||||
            KclError::Engine(KclErrorDetails {
 | 
			
		||||
                message: format!("Failed to send modeling command: {}", e),
 | 
			
		||||
                source_ranges: vec![source_range],
 | 
			
		||||
            })
 | 
			
		||||
        })?;
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Headers for starting a websocket session with api-deux.
 | 
			
		||||
fn websocket_headers<'a>(
 | 
			
		||||
    token: &'a str,
 | 
			
		||||
    key: &'a str,
 | 
			
		||||
    origin: &'a str,
 | 
			
		||||
) -> [httparse::Header<'a>; 6] {
 | 
			
		||||
    [
 | 
			
		||||
        httparse::Header {
 | 
			
		||||
            name: "Authorization",
 | 
			
		||||
            value: token.as_bytes(),
 | 
			
		||||
        },
 | 
			
		||||
        httparse::Header {
 | 
			
		||||
            name: "Connection",
 | 
			
		||||
            value: b"Upgrade",
 | 
			
		||||
        },
 | 
			
		||||
        httparse::Header {
 | 
			
		||||
            name: "Upgrade",
 | 
			
		||||
            value: b"websocket",
 | 
			
		||||
        },
 | 
			
		||||
        httparse::Header {
 | 
			
		||||
            name: "Sec-WebSocket-Version",
 | 
			
		||||
            value: b"13",
 | 
			
		||||
        },
 | 
			
		||||
        httparse::Header {
 | 
			
		||||
            name: "Sec-WebSocket-Key",
 | 
			
		||||
            value: key.as_bytes(),
 | 
			
		||||
        },
 | 
			
		||||
        httparse::Header {
 | 
			
		||||
            name: "Host",
 | 
			
		||||
            value: origin.as_bytes(),
 | 
			
		||||
        },
 | 
			
		||||
    ]
 | 
			
		||||
}
 | 
			
		||||
@ -1,25 +0,0 @@
 | 
			
		||||
//! Functions for exported files from the server.
 | 
			
		||||
 | 
			
		||||
use gloo_utils::format::JsValueSerdeExt;
 | 
			
		||||
use wasm_bindgen::prelude::*;
 | 
			
		||||
 | 
			
		||||
#[wasm_bindgen]
 | 
			
		||||
pub fn deserialize_files(data: &[u8]) -> Result<JsValue, JsError> {
 | 
			
		||||
    let ws_resp: kittycad::types::WebSocketResponse = bincode::deserialize(data)?;
 | 
			
		||||
 | 
			
		||||
    if !ws_resp.success {
 | 
			
		||||
        return Err(JsError::new(&format!(
 | 
			
		||||
            "Server returned error: {:?}",
 | 
			
		||||
            ws_resp.errors
 | 
			
		||||
        )));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if let Some(kittycad::types::OkWebSocketResponseData::Export { files }) = ws_resp.resp {
 | 
			
		||||
        return Ok(JsValue::from_serde(&files)?);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Err(JsError::new(&format!(
 | 
			
		||||
        "Invalid response type, got: {:?}",
 | 
			
		||||
        ws_resp
 | 
			
		||||
    )))
 | 
			
		||||
}
 | 
			
		||||
@ -1,11 +1,84 @@
 | 
			
		||||
mod abstract_syntax_tree_types;
 | 
			
		||||
mod docs;
 | 
			
		||||
mod engine;
 | 
			
		||||
mod errors;
 | 
			
		||||
mod executor;
 | 
			
		||||
mod export;
 | 
			
		||||
mod math_parser;
 | 
			
		||||
mod parser;
 | 
			
		||||
mod recast;
 | 
			
		||||
mod std;
 | 
			
		||||
mod tokeniser;
 | 
			
		||||
//! Wasm bindings for `kcl`.
 | 
			
		||||
 | 
			
		||||
use gloo_utils::format::JsValueSerdeExt;
 | 
			
		||||
use wasm_bindgen::prelude::*;
 | 
			
		||||
 | 
			
		||||
// wasm_bindgen wrapper for execute
 | 
			
		||||
#[cfg(target_arch = "wasm32")]
 | 
			
		||||
#[wasm_bindgen]
 | 
			
		||||
pub async fn execute_wasm(
 | 
			
		||||
    program_str: &str,
 | 
			
		||||
    memory_str: &str,
 | 
			
		||||
    manager: kcl::engine::conn_wasm::EngineCommandManager,
 | 
			
		||||
) -> Result<JsValue, String> {
 | 
			
		||||
    // deserialize the ast from a stringified json
 | 
			
		||||
    let program: kcl::abstract_syntax_tree_types::Program =
 | 
			
		||||
        serde_json::from_str(program_str).map_err(|e| e.to_string())?;
 | 
			
		||||
    let mut mem: kcl::executor::ProgramMemory =
 | 
			
		||||
        serde_json::from_str(memory_str).map_err(|e| e.to_string())?;
 | 
			
		||||
 | 
			
		||||
    let mut engine = kcl::engine::EngineConnection::new(manager)
 | 
			
		||||
        .await
 | 
			
		||||
        .map_err(|e| format!("{:?}", e))?;
 | 
			
		||||
 | 
			
		||||
    let memory = kcl::executor::execute(
 | 
			
		||||
        program,
 | 
			
		||||
        &mut mem,
 | 
			
		||||
        kcl::executor::BodyType::Root,
 | 
			
		||||
        &mut engine,
 | 
			
		||||
    )
 | 
			
		||||
    .map_err(String::from)?;
 | 
			
		||||
    // The serde-wasm-bindgen does not work here because of weird HashMap issues so we use the
 | 
			
		||||
    // gloo-serialize crate instead.
 | 
			
		||||
    JsValue::from_serde(&memory).map_err(|e| e.to_string())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[wasm_bindgen]
 | 
			
		||||
pub fn deserialize_files(data: &[u8]) -> Result<JsValue, JsError> {
 | 
			
		||||
    let ws_resp: kittycad::types::WebSocketResponse = bson::from_slice(data)?;
 | 
			
		||||
 | 
			
		||||
    if !ws_resp.success {
 | 
			
		||||
        return Err(JsError::new(&format!(
 | 
			
		||||
            "Server returned error: {:?}",
 | 
			
		||||
            ws_resp.errors
 | 
			
		||||
        )));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if let Some(kittycad::types::OkWebSocketResponseData::Export { files }) = ws_resp.resp {
 | 
			
		||||
        return Ok(JsValue::from_serde(&files)?);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Err(JsError::new(&format!(
 | 
			
		||||
        "Invalid response type, got: {:?}",
 | 
			
		||||
        ws_resp
 | 
			
		||||
    )))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// wasm_bindgen wrapper for lexer
 | 
			
		||||
// test for this function and by extension lexer are done in javascript land src/lang/tokeniser.test.ts
 | 
			
		||||
#[wasm_bindgen]
 | 
			
		||||
pub fn lexer_js(js: &str) -> Result<JsValue, JsError> {
 | 
			
		||||
    let tokens = kcl::tokeniser::lexer(js);
 | 
			
		||||
    Ok(JsValue::from_serde(&tokens)?)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[wasm_bindgen]
 | 
			
		||||
pub fn parse_js(js: &str) -> Result<JsValue, String> {
 | 
			
		||||
    let tokens = kcl::tokeniser::lexer(js);
 | 
			
		||||
    let program = kcl::parser::abstract_syntax_tree(&tokens).map_err(String::from)?;
 | 
			
		||||
    // The serde-wasm-bindgen does not work here because of weird HashMap issues so we use the
 | 
			
		||||
    // gloo-serialize crate instead.
 | 
			
		||||
    JsValue::from_serde(&program).map_err(|e| e.to_string())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// wasm_bindgen wrapper for recast
 | 
			
		||||
// test for this function and by extension the recaster are done in javascript land src/lang/recast.test.ts
 | 
			
		||||
#[wasm_bindgen]
 | 
			
		||||
pub fn recast_wasm(json_str: &str) -> Result<JsValue, JsError> {
 | 
			
		||||
    // deserialize the ast from a stringified json
 | 
			
		||||
    let program: kcl::abstract_syntax_tree_types::Program =
 | 
			
		||||
        serde_json::from_str(json_str).map_err(JsError::from)?;
 | 
			
		||||
 | 
			
		||||
    let result = kcl::recast::recast(&program, "", false);
 | 
			
		||||
    Ok(JsValue::from_serde(&result)?)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user