Compare commits
39 Commits
fillet-err
...
jess/chang
Author | SHA1 | Date | |
---|---|---|---|
495727d617 | |||
e943303434 | |||
8ce175f006 | |||
13aa178734 | |||
de137ff13b | |||
48e1a8ed02 | |||
a059166b9c | |||
086a2b851d | |||
8e4c5fb24d | |||
6993893600 | |||
bfdf8babed | |||
3504b9246f | |||
a035f7879b | |||
d122d7a224 | |||
198e7c4bd2 | |||
14d8903acc | |||
275c23f294 | |||
0ac9ac3896 | |||
0220d0f9de | |||
4523dc209b | |||
ea73eb011c | |||
0aa2824c20 | |||
e66893c5d0 | |||
60274127df | |||
a0d1750829 | |||
00ffa8c0bf | |||
fafdf41093 | |||
a2092e7ed6 | |||
aa103d299c | |||
aaaab495bc | |||
364e38fda2 | |||
b085af139b | |||
ec537cd8dc | |||
8debbc5241 | |||
a590ed99cf | |||
a002bb60a0 | |||
6ba01b8dfa | |||
ca9e6e0944 | |||
e85e54215c |
4
.github/workflows/e2e-tests.yml
vendored
4
.github/workflows/e2e-tests.yml
vendored
@ -281,7 +281,7 @@ jobs:
|
||||
os:
|
||||
- "runs-on=${{ github.run_id }}/family=i7ie.2xlarge/image=ubuntu22-full-x64"
|
||||
- namespace-profile-macos-8-cores
|
||||
- windows-latest
|
||||
- windows-latest-8-cores
|
||||
shardIndex: [1, 2, 3, 4]
|
||||
shardTotal: [4]
|
||||
# Disable macos and windows tests on hourly e2e tests since we only care
|
||||
@ -292,7 +292,7 @@ jobs:
|
||||
exclude:
|
||||
- os: namespace-profile-macos-8-cores
|
||||
isScheduled: true
|
||||
- os: windows-latest
|
||||
- os: windows-latest-8-cores
|
||||
isScheduled: true
|
||||
# TODO: add ref here for main and latest release tag
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
File diff suppressed because one or more lines are too long
@ -32,53 +32,44 @@ test(
|
||||
})
|
||||
await page.setBodyDimensions({ width: 1200, height: 500 })
|
||||
|
||||
page.on('console', console.log)
|
||||
|
||||
await test.step('on open of project', async () => {
|
||||
await expect(page.getByText(`bracket`)).toBeVisible()
|
||||
// Open the project
|
||||
const projectName = page.getByText(`bracket`)
|
||||
await expect(projectName).toBeVisible()
|
||||
await projectName.click()
|
||||
await scene.waitForExecutionDone()
|
||||
await page.waitForTimeout(1_000) // wait for panel buttons to be available
|
||||
|
||||
// open the project
|
||||
await page.getByText(`bracket`).click()
|
||||
|
||||
// expect zero errors in guter
|
||||
// Expect zero errors in gutter
|
||||
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
||||
|
||||
// export the model
|
||||
// Click the export button
|
||||
const exportButton = page.getByTestId('export-pane-button')
|
||||
await expect(exportButton).toBeVisible()
|
||||
|
||||
await scene.waitForExecutionDone()
|
||||
|
||||
const gltfOption = page.getByText('glTF')
|
||||
const submitButton = page.getByText('Confirm Export')
|
||||
const exportingToastMessage = page.getByText(`Exporting...`)
|
||||
const errorToastMessage = page.getByText(`Error while exporting`)
|
||||
const engineErrorToastMessage = page.getByText(`Nothing to export`)
|
||||
const alreadyExportingToastMessage = page.getByText(`Already exporting`)
|
||||
// The open file's name is `main.kcl`, so the export file name should be `main.gltf`
|
||||
const exportFileName = `main.gltf`
|
||||
|
||||
// Click the export button
|
||||
await exportButton.click()
|
||||
await page.waitForTimeout(1_000) // wait for export options to be available
|
||||
|
||||
// Select the first format option
|
||||
const gltfOption = page.getByText('glTF')
|
||||
const exportFileName = `main.gltf` // source file is named `main.kcl`
|
||||
await expect(gltfOption).toBeVisible()
|
||||
await expect(page.getByText('STL')).toBeVisible()
|
||||
|
||||
await page.keyboard.press('Enter')
|
||||
|
||||
// Click the checkbox
|
||||
const submitButton = page.getByText('Confirm Export')
|
||||
await expect(submitButton).toBeVisible()
|
||||
|
||||
await page.waitForTimeout(500)
|
||||
|
||||
await page.keyboard.press('Enter')
|
||||
|
||||
// Find the toast.
|
||||
// Look out for the toast message
|
||||
const exportingToastMessage = page.getByText(`Exporting...`)
|
||||
const alreadyExportingToastMessage = page.getByText(`Already exporting`)
|
||||
await expect(exportingToastMessage).toBeVisible()
|
||||
await expect(alreadyExportingToastMessage).not.toBeVisible()
|
||||
|
||||
// Expect it to succeed.
|
||||
// Expect it to succeed
|
||||
const errorToastMessage = page.getByText(`Error while exporting`)
|
||||
const engineErrorToastMessage = page.getByText(`Nothing to export`)
|
||||
await expect(errorToastMessage).not.toBeVisible()
|
||||
await expect(engineErrorToastMessage).not.toBeVisible()
|
||||
|
||||
@ -86,6 +77,7 @@ test(
|
||||
await expect(successToastMessage).toBeVisible()
|
||||
await expect(exportingToastMessage).not.toBeVisible()
|
||||
|
||||
// Check for the exported file
|
||||
const firstFileFullPath = path.resolve(
|
||||
getPlaywrightDownloadDir(tronApp.projectDirName),
|
||||
exportFileName
|
||||
@ -112,60 +104,53 @@ test(
|
||||
const u = await getUtils(page)
|
||||
await u.openFilePanel()
|
||||
|
||||
// Click on the other file
|
||||
const otherKclButton = page.getByRole('button', { name: 'other.kcl' })
|
||||
|
||||
// Click the file
|
||||
await otherKclButton.click()
|
||||
|
||||
// Close the file pane
|
||||
await u.closeFilePanel()
|
||||
await scene.waitForExecutionDone()
|
||||
await page.waitForTimeout(1_000) // wait for panel buttons to be available
|
||||
|
||||
// FIXME: await scene.waitForExecutionDone() does not work. The modeling indicator stays in -receive-reliable and not execution done
|
||||
await page.waitForTimeout(10000)
|
||||
|
||||
// expect zero errors in guter
|
||||
// Expect zero errors in gutter
|
||||
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
|
||||
|
||||
// export the model
|
||||
// Click the export button
|
||||
const exportButton = page.getByTestId('export-pane-button')
|
||||
await expect(exportButton).toBeVisible()
|
||||
|
||||
const gltfOption = page.getByText('glTF')
|
||||
const submitButton = page.getByText('Confirm Export')
|
||||
const exportingToastMessage = page.getByText(`Exporting...`)
|
||||
const errorToastMessage = page.getByText(`Error while exporting`)
|
||||
const engineErrorToastMessage = page.getByText(`Nothing to export`)
|
||||
const alreadyExportingToastMessage = page.getByText(`Already exporting`)
|
||||
// The open file's name is `other.kcl`, so the export file name should be `other.gltf`
|
||||
const exportFileName = `other.gltf`
|
||||
|
||||
// Click the export button
|
||||
await exportButton.click()
|
||||
await page.waitForTimeout(1_000) // wait for export options to be available
|
||||
|
||||
// Select the first format option
|
||||
const gltfOption = page.getByText('glTF')
|
||||
const exportFileName = `other.gltf` // source file is named `other.kcl`
|
||||
await expect(gltfOption).toBeVisible()
|
||||
await expect(page.getByText('STL')).toBeVisible()
|
||||
|
||||
await page.keyboard.press('Enter')
|
||||
|
||||
// Click the checkbox
|
||||
const submitButton = page.getByText('Confirm Export')
|
||||
await expect(submitButton).toBeVisible()
|
||||
|
||||
await page.waitForTimeout(500)
|
||||
await page.keyboard.press('Enter')
|
||||
|
||||
// Find the toast.
|
||||
// Look out for the toast message
|
||||
const exportingToastMessage = page.getByText(`Exporting...`)
|
||||
const alreadyExportingToastMessage = page.getByText(`Already exporting`)
|
||||
await expect(exportingToastMessage).toBeVisible()
|
||||
await expect(alreadyExportingToastMessage).not.toBeVisible()
|
||||
|
||||
// Expect it to succeed
|
||||
const errorToastMessage = page.getByText(`Error while exporting`)
|
||||
const engineErrorToastMessage = page.getByText(`Nothing to export`)
|
||||
await expect(errorToastMessage).not.toBeVisible()
|
||||
await expect(engineErrorToastMessage).not.toBeVisible()
|
||||
|
||||
const successToastMessage = page.getByText(`Exported successfully`)
|
||||
await test.step('Check the success toast message shows and nothing else', async () =>
|
||||
Promise.all([
|
||||
expect(alreadyExportingToastMessage).not.toBeVisible(),
|
||||
expect(errorToastMessage).not.toBeVisible(),
|
||||
expect(engineErrorToastMessage).not.toBeVisible(),
|
||||
expect(successToastMessage).toBeVisible(),
|
||||
expect(exportingToastMessage).not.toBeVisible(),
|
||||
]))
|
||||
await expect(successToastMessage).toBeVisible()
|
||||
await expect(exportingToastMessage).not.toBeVisible()
|
||||
|
||||
// Check for the exported file=
|
||||
const secondFileFullPath = path.resolve(
|
||||
getPlaywrightDownloadDir(tronApp.projectDirName),
|
||||
exportFileName
|
||||
|
@ -1315,4 +1315,38 @@ sketch001 = startSketchOn(XZ)
|
||||
const element = page.locator('[data-overlay-index="1"]')
|
||||
await expect(element).toHaveAttribute('data-overlay-visible', 'true')
|
||||
})
|
||||
|
||||
test(`Only show axis planes when there are no errors`, async ({
|
||||
page,
|
||||
homePage,
|
||||
scene,
|
||||
cmdBar,
|
||||
}) => {
|
||||
await page.addInitScript(async () => {
|
||||
localStorage.setItem(
|
||||
'persistCode',
|
||||
`sketch001 = startSketchOn(XZ)
|
||||
profile001 = circle(sketch001, center = [-100.0, -100.0], radius = 50.0)
|
||||
|
||||
sketch002 = startSketchOn(XZ)
|
||||
profile002 = circle(sketch002, center = [-100.0, 100.0], radius = 50.0)
|
||||
extrude001 = extrude(profile002, length = 0)` // length = 0 is causing the error
|
||||
)
|
||||
})
|
||||
|
||||
const viewportSize = { width: 1200, height: 800 }
|
||||
await page.setBodyDimensions(viewportSize)
|
||||
|
||||
await homePage.goToModelingScene()
|
||||
|
||||
await scene.connectionEstablished()
|
||||
await scene.settled(cmdBar)
|
||||
|
||||
await scene.expectPixelColor(
|
||||
TEST_COLORS.DARK_MODE_BKGD,
|
||||
// This is a position where the blue part of the axis plane is visible if its rendered
|
||||
{ x: viewportSize.width * 0.75, y: viewportSize.height * 0.2 },
|
||||
15
|
||||
)
|
||||
})
|
||||
})
|
||||
|
@ -8,8 +8,8 @@ import { expect, test } from '@e2e/playwright/zoo-test'
|
||||
|
||||
test.describe('Testing in-app sample loading', () => {
|
||||
/**
|
||||
* Note this test implicitly depends on the KCL sample "a-parametric-bearing-pillow-block",
|
||||
* its title, and its units settings. https://github.com/KittyCAD/kcl-samples/blob/main/a-parametric-bearing-pillow-block/main.kcl
|
||||
* Note this test implicitly depends on the KCL sample "parametric-bearing-pillow-block",
|
||||
* its title, and its units settings. https://github.com/KittyCAD/kcl-samples/blob/main/parametric-bearing-pillow-block/main.kcl
|
||||
*/
|
||||
test('Web: should overwrite current code, cannot create new file', async ({
|
||||
editor,
|
||||
@ -29,8 +29,8 @@ test.describe('Testing in-app sample loading', () => {
|
||||
|
||||
// Locators and constants
|
||||
const newSample = {
|
||||
file: 'a-parametric-bearing-pillow-block' + FILE_EXT,
|
||||
title: 'A Parametric Bearing Pillow Block',
|
||||
file: 'parametric-bearing-pillow-block' + FILE_EXT,
|
||||
title: 'Parametric Bearing Pillow Block',
|
||||
}
|
||||
const commandBarButton = page.getByRole('button', { name: 'Commands' })
|
||||
const samplesCommandOption = page.getByRole('option', {
|
||||
@ -72,7 +72,7 @@ test.describe('Testing in-app sample loading', () => {
|
||||
|
||||
/**
|
||||
* Note this test implicitly depends on the KCL samples:
|
||||
* "a-parametric-bearing-pillow-block": https://github.com/KittyCAD/kcl-samples/blob/main/a-parametric-bearing-pillow-block/main.kcl
|
||||
* "parametric-bearing-pillow-block": https://github.com/KittyCAD/kcl-samples/blob/main/parametric-bearing-pillow-block/main.kcl
|
||||
* "gear-rack": https://github.com/KittyCAD/kcl-samples/blob/main/gear-rack/main.kcl
|
||||
*/
|
||||
test(
|
||||
@ -90,8 +90,8 @@ test.describe('Testing in-app sample loading', () => {
|
||||
|
||||
// Locators and constants
|
||||
const sampleOne = {
|
||||
file: 'a-parametric-bearing-pillow-block' + FILE_EXT,
|
||||
title: 'A Parametric Bearing Pillow Block',
|
||||
file: 'parametric-bearing-pillow-block' + FILE_EXT,
|
||||
title: 'Parametric Bearing Pillow Block',
|
||||
}
|
||||
const sampleTwo = {
|
||||
file: 'gear-rack' + FILE_EXT,
|
||||
|
@ -4,6 +4,7 @@ directories:
|
||||
buildResources: assets
|
||||
files:
|
||||
- .vite/**
|
||||
- "!node_modules/win-ca/pem/**"
|
||||
mac:
|
||||
category: public.app-category.developer-tools
|
||||
artifactName: "${productName}-${version}-${arch}-${os}.${ext}"
|
||||
|
@ -66,6 +66,7 @@
|
||||
"vscode-languageserver-protocol": "^3.17.5",
|
||||
"vscode-uri": "^3.1.0",
|
||||
"web-vitals": "^3.5.2",
|
||||
"win-ca": "^3.5.1",
|
||||
"xstate": "^5.19.2",
|
||||
"yargs": "^17.7.2"
|
||||
},
|
||||
|
@ -94,4 +94,4 @@ outsideWallSketch = startSketchOn(offsetPlane(XY, offset = -overallThickness / 2
|
||||
|> circle(center = [0, 0], radius = outsideDiameter / 2)
|
||||
|> hole(circle(center = [0, 0], radius = shaftDia / 2 + wallThickness + sphereDia), %)
|
||||
|
||||
outsideWall = extrude(outsideWallSketch, length = overallThickness)
|
||||
outsideWall = extrude(outsideWallSketch, length = overallThickness)
|
||||
|
@ -21,7 +21,7 @@ archThickness = 1
|
||||
archRadius = mirrorRadius + archToMirrorGap
|
||||
|
||||
// Geometry
|
||||
// Add a function to create the hinge
|
||||
// Add a function to create the hinge
|
||||
fn hingeFn(x, y, z) {
|
||||
hingeBody = startSketchOn(offsetPlane(XY, offset = z))
|
||||
|> circle(center = [x, y], radius = hingeRadius)
|
||||
|
@ -9,7 +9,6 @@ import pipeInnerDiameter, pipeOuterDiameter, pipeLength from "parameters.kcl"
|
||||
|
||||
// Create a function to make the pipe. Export
|
||||
export fn pipe() {
|
||||
|
||||
// Create the pipe base
|
||||
pipeBase = startSketchOn(XZ)
|
||||
|> circle(%, center = [0, 0], radius = pipeOuterDiameter / 2)
|
||||
|
@ -9,7 +9,6 @@ import pipeDiameter, mountingHoleDiameter, mountingHolePlacementDiameter, flange
|
||||
|
||||
// Create a function to create the flange. We must create a function since we are using multiple flanges.
|
||||
export fn flange() {
|
||||
|
||||
// Sketch the mounting hole pattern
|
||||
mountingHoles = startSketchOn(XY)
|
||||
|> circle(%, center = [0, mountingHolePlacementDiameter / 2], radius = mountingHoleDiameter / 2)
|
||||
@ -42,4 +41,4 @@ export fn flange() {
|
||||
|> appearance(%, color = "#bab0b0")
|
||||
|
||||
return pipeCut
|
||||
}
|
||||
}
|
||||
|
@ -9,7 +9,6 @@ import hexNutDiameter, hexNutFlatToFlat, hexNutThickness, hexNutFlatLength from
|
||||
|
||||
// Create a function to make the hex nut. Must be a function since multiple hex nuts are used
|
||||
export fn hexNut() {
|
||||
|
||||
// Create the base of the hex nut
|
||||
hexNutBase = startSketchOn(XY)
|
||||
|> startProfileAt([
|
||||
|
@ -7,7 +7,7 @@
|
||||
// Import parameters
|
||||
import washerInnerDia, washerOuterDia, washerThickness from "parameters.kcl"
|
||||
|
||||
// Create a function to make the washer. Must be a function since multiple washers are used.
|
||||
// Create a function to make the washer. Must be a function since multiple washers are used.
|
||||
export fn washer() {
|
||||
// Create the base of the washer
|
||||
washerBase = startSketchOn(XY)
|
||||
|
@ -8,7 +8,7 @@
|
||||
import * from "parameters.kcl"
|
||||
|
||||
// Import parts
|
||||
import '9472k188-gasket.kcl' as gasket
|
||||
import "9472k188-gasket.kcl" as gasket
|
||||
import flange from "68095k348-flange.kcl"
|
||||
import washer from "98017a257-washer.kcl"
|
||||
import bolt from "91251a404-bolt.kcl"
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 69 KiB |
20
rust/Cargo.lock
generated
20
rust/Cargo.lock
generated
@ -1907,6 +1907,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"tabled",
|
||||
"tempdir",
|
||||
"thiserror 2.0.12",
|
||||
"tokio",
|
||||
"tokio-tungstenite",
|
||||
@ -3084,6 +3085,15 @@ version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.12.15"
|
||||
@ -3779,6 +3789,16 @@ version = "0.13.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e502f78cdbb8ba4718f566c418c52bc729126ffd16baee5baa718cf25dd5a69a"
|
||||
|
||||
[[package]]
|
||||
name = "tempdir"
|
||||
version = "0.3.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
|
||||
dependencies = [
|
||||
"rand 0.4.6",
|
||||
"remove_dir_all",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.19.0"
|
||||
|
@ -22,7 +22,6 @@ debug = 0
|
||||
|
||||
[profile.dev.package]
|
||||
insta = { opt-level = 3 }
|
||||
similar = { opt-level = 3 }
|
||||
|
||||
[profile.test]
|
||||
debug = "line-tables-only"
|
||||
|
@ -69,6 +69,7 @@ serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
sha2 = "0.10.8"
|
||||
tabled = { version = "0.18.0", optional = true }
|
||||
tempdir = "0.3.7"
|
||||
thiserror = "2.0.0"
|
||||
toml = "0.8.19"
|
||||
ts-rs = { version = "10.1.0", features = [
|
||||
|
@ -18,7 +18,7 @@ use tokio::sync::{mpsc, oneshot, RwLock};
|
||||
use tokio_tungstenite::tungstenite::Message as WsMsg;
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::{EngineStats, ExecutionKind};
|
||||
use super::EngineStats;
|
||||
use crate::{
|
||||
engine::EngineManager,
|
||||
errors::{KclError, KclErrorDetails},
|
||||
@ -51,7 +51,6 @@ pub struct EngineConnection {
|
||||
/// If the server sends session data, it'll be copied to here.
|
||||
session_data: Arc<RwLock<Option<ModelingSessionData>>>,
|
||||
|
||||
execution_kind: Arc<RwLock<ExecutionKind>>,
|
||||
stats: EngineStats,
|
||||
}
|
||||
|
||||
@ -344,7 +343,6 @@ impl EngineConnection {
|
||||
artifact_commands: Arc::new(RwLock::new(Vec::new())),
|
||||
default_planes: Default::default(),
|
||||
session_data,
|
||||
execution_kind: Default::default(),
|
||||
stats: Default::default(),
|
||||
})
|
||||
}
|
||||
@ -368,18 +366,6 @@ impl EngineManager for EngineConnection {
|
||||
self.artifact_commands.clone()
|
||||
}
|
||||
|
||||
async fn execution_kind(&self) -> ExecutionKind {
|
||||
let guard = self.execution_kind.read().await;
|
||||
*guard
|
||||
}
|
||||
|
||||
async fn replace_execution_kind(&self, execution_kind: ExecutionKind) -> ExecutionKind {
|
||||
let mut guard = self.execution_kind.write().await;
|
||||
let original = *guard;
|
||||
*guard = execution_kind;
|
||||
original
|
||||
}
|
||||
|
||||
fn stats(&self) -> &EngineStats {
|
||||
&self.stats
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ use kittycad_modeling_cmds::{self as kcmc};
|
||||
use tokio::sync::RwLock;
|
||||
use uuid::Uuid;
|
||||
|
||||
use super::{EngineStats, ExecutionKind};
|
||||
use super::EngineStats;
|
||||
use crate::{
|
||||
errors::KclError,
|
||||
exec::DefaultPlanes,
|
||||
@ -29,7 +29,6 @@ pub struct EngineConnection {
|
||||
batch: Arc<RwLock<Vec<(WebSocketRequest, SourceRange)>>>,
|
||||
batch_end: Arc<RwLock<IndexMap<uuid::Uuid, (WebSocketRequest, SourceRange)>>>,
|
||||
artifact_commands: Arc<RwLock<Vec<ArtifactCommand>>>,
|
||||
execution_kind: Arc<RwLock<ExecutionKind>>,
|
||||
/// The default planes for the scene.
|
||||
default_planes: Arc<RwLock<Option<DefaultPlanes>>>,
|
||||
stats: EngineStats,
|
||||
@ -41,7 +40,6 @@ impl EngineConnection {
|
||||
batch: Arc::new(RwLock::new(Vec::new())),
|
||||
batch_end: Arc::new(RwLock::new(IndexMap::new())),
|
||||
artifact_commands: Arc::new(RwLock::new(Vec::new())),
|
||||
execution_kind: Default::default(),
|
||||
default_planes: Default::default(),
|
||||
stats: Default::default(),
|
||||
})
|
||||
@ -70,18 +68,6 @@ impl crate::engine::EngineManager for EngineConnection {
|
||||
self.artifact_commands.clone()
|
||||
}
|
||||
|
||||
async fn execution_kind(&self) -> ExecutionKind {
|
||||
let guard = self.execution_kind.read().await;
|
||||
*guard
|
||||
}
|
||||
|
||||
async fn replace_execution_kind(&self, execution_kind: ExecutionKind) -> ExecutionKind {
|
||||
let mut guard = self.execution_kind.write().await;
|
||||
let original = *guard;
|
||||
*guard = execution_kind;
|
||||
original
|
||||
}
|
||||
|
||||
fn get_default_planes(&self) -> Arc<RwLock<Option<DefaultPlanes>>> {
|
||||
self.default_planes.clone()
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ use uuid::Uuid;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
use crate::{
|
||||
engine::{EngineStats, ExecutionKind},
|
||||
engine::EngineStats,
|
||||
errors::{KclError, KclErrorDetails},
|
||||
execution::{ArtifactCommand, DefaultPlanes, IdGenerator},
|
||||
SourceRange,
|
||||
@ -42,7 +42,6 @@ pub struct EngineConnection {
|
||||
batch_end: Arc<RwLock<IndexMap<uuid::Uuid, (WebSocketRequest, SourceRange)>>>,
|
||||
responses: Arc<RwLock<IndexMap<Uuid, WebSocketResponse>>>,
|
||||
artifact_commands: Arc<RwLock<Vec<ArtifactCommand>>>,
|
||||
execution_kind: Arc<RwLock<ExecutionKind>>,
|
||||
/// The default planes for the scene.
|
||||
default_planes: Arc<RwLock<Option<DefaultPlanes>>>,
|
||||
stats: EngineStats,
|
||||
@ -61,7 +60,6 @@ impl EngineConnection {
|
||||
batch_end: Arc::new(RwLock::new(IndexMap::new())),
|
||||
responses: Arc::new(RwLock::new(IndexMap::new())),
|
||||
artifact_commands: Arc::new(RwLock::new(Vec::new())),
|
||||
execution_kind: Default::default(),
|
||||
default_planes: Default::default(),
|
||||
stats: Default::default(),
|
||||
})
|
||||
@ -164,18 +162,6 @@ impl crate::engine::EngineManager for EngineConnection {
|
||||
self.artifact_commands.clone()
|
||||
}
|
||||
|
||||
async fn execution_kind(&self) -> ExecutionKind {
|
||||
let guard = self.execution_kind.read().await;
|
||||
*guard
|
||||
}
|
||||
|
||||
async fn replace_execution_kind(&self, execution_kind: ExecutionKind) -> ExecutionKind {
|
||||
let mut guard = self.execution_kind.write().await;
|
||||
let original = *guard;
|
||||
*guard = execution_kind;
|
||||
original
|
||||
}
|
||||
|
||||
fn get_default_planes(&self) -> Arc<RwLock<Option<DefaultPlanes>>> {
|
||||
self.default_planes.clone()
|
||||
}
|
||||
@ -218,11 +204,6 @@ impl crate::engine::EngineManager for EngineConnection {
|
||||
.do_send_modeling_cmd(id, source_range, cmd, id_to_source_range)
|
||||
.await?;
|
||||
|
||||
// In isolated mode, we don't save the response.
|
||||
if self.execution_kind().await.is_isolated() {
|
||||
return Ok(ws_result);
|
||||
}
|
||||
|
||||
let mut responses = self.responses.write().await;
|
||||
responses.insert(id, ws_result.clone());
|
||||
drop(responses);
|
||||
|
@ -47,23 +47,6 @@ lazy_static::lazy_static! {
|
||||
pub static ref GRID_SCALE_TEXT_OBJECT_ID: uuid::Uuid = uuid::Uuid::parse_str("10782f33-f588-4668-8bcd-040502d26590").unwrap();
|
||||
}
|
||||
|
||||
/// The mode of execution. When isolated, like during an import, attempting to
|
||||
/// send a command results in an error.
|
||||
#[derive(Debug, Default, Clone, Copy, Deserialize, Serialize, PartialEq, Eq, ts_rs::TS, JsonSchema)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum ExecutionKind {
|
||||
#[default]
|
||||
Normal,
|
||||
Isolated,
|
||||
}
|
||||
|
||||
impl ExecutionKind {
|
||||
pub fn is_isolated(&self) -> bool {
|
||||
matches!(self, ExecutionKind::Isolated)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct EngineStats {
|
||||
pub commands_batched: AtomicUsize,
|
||||
@ -108,13 +91,6 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
|
||||
std::mem::take(&mut *self.responses().write().await)
|
||||
}
|
||||
|
||||
/// Get the current execution kind.
|
||||
async fn execution_kind(&self) -> ExecutionKind;
|
||||
|
||||
/// Replace the current execution kind with a new value and return the
|
||||
/// existing value.
|
||||
async fn replace_execution_kind(&self, execution_kind: ExecutionKind) -> ExecutionKind;
|
||||
|
||||
/// Get the default planes.
|
||||
fn get_default_planes(&self) -> Arc<RwLock<Option<DefaultPlanes>>>;
|
||||
|
||||
@ -279,11 +255,6 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
|
||||
source_range: SourceRange,
|
||||
cmd: &ModelingCmd,
|
||||
) -> Result<(), crate::errors::KclError> {
|
||||
// In isolated mode, we don't send the command to the engine.
|
||||
if self.execution_kind().await.is_isolated() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let req = WebSocketRequest::ModelingCmdReq(ModelingCmdReq {
|
||||
cmd: cmd.clone(),
|
||||
cmd_id: id.into(),
|
||||
@ -305,11 +276,6 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
|
||||
source_range: SourceRange,
|
||||
cmds: &[ModelingCmdReq],
|
||||
) -> Result<(), crate::errors::KclError> {
|
||||
// In isolated mode, we don't send the command to the engine.
|
||||
if self.execution_kind().await.is_isolated() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// Add cmds to the batch.
|
||||
let mut extended_cmds = Vec::with_capacity(cmds.len());
|
||||
for cmd in cmds {
|
||||
@ -332,11 +298,6 @@ pub trait EngineManager: std::fmt::Debug + Send + Sync + 'static {
|
||||
source_range: SourceRange,
|
||||
cmd: &ModelingCmd,
|
||||
) -> Result<(), crate::errors::KclError> {
|
||||
// In isolated mode, we don't send the command to the engine.
|
||||
if self.execution_kind().await.is_isolated() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let req = WebSocketRequest::ModelingCmdReq(ModelingCmdReq {
|
||||
cmd: cmd.clone(),
|
||||
cmd_id: id.into(),
|
||||
|
@ -5,7 +5,6 @@ use indexmap::IndexMap;
|
||||
|
||||
use super::{cad_op::Group, kcl_value::TypeDef, types::PrimitiveType};
|
||||
use crate::{
|
||||
engine::ExecutionKind,
|
||||
errors::{KclError, KclErrorDetails},
|
||||
execution::{
|
||||
annotations,
|
||||
@ -62,15 +61,13 @@ impl ExecutorContext {
|
||||
exec_state.mod_local.explicit_length_units = true;
|
||||
}
|
||||
let new_units = exec_state.length_unit();
|
||||
if !self.engine.execution_kind().await.is_isolated() {
|
||||
self.engine
|
||||
.set_units(
|
||||
new_units.into(),
|
||||
annotation.as_source_range(),
|
||||
exec_state.id_generator(),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
self.engine
|
||||
.set_units(
|
||||
new_units.into(),
|
||||
annotation.as_source_range(),
|
||||
exec_state.id_generator(),
|
||||
)
|
||||
.await?;
|
||||
} else {
|
||||
exec_state.err(CompilationError::err(
|
||||
annotation.as_source_range(),
|
||||
@ -100,15 +97,13 @@ impl ExecutorContext {
|
||||
&self,
|
||||
program: &Node<Program>,
|
||||
exec_state: &mut ExecState,
|
||||
exec_kind: ExecutionKind,
|
||||
preserve_mem: bool,
|
||||
module_id: ModuleId,
|
||||
path: &ModulePath,
|
||||
) -> Result<(Option<KclValue>, EnvironmentRef, Vec<String>), KclError> {
|
||||
crate::log::log(format!("enter module {path} {} {exec_kind:?}", exec_state.stack()));
|
||||
crate::log::log(format!("enter module {path} {}", exec_state.stack()));
|
||||
|
||||
let old_units = exec_state.length_unit();
|
||||
let original_execution = self.engine.replace_execution_kind(exec_kind).await;
|
||||
|
||||
let mut local_state = ModuleState::new(path.std_path(), exec_state.stack().memory.clone(), Some(module_id));
|
||||
if !preserve_mem {
|
||||
@ -141,23 +136,71 @@ impl ExecutorContext {
|
||||
// If we reset at the end of the main path, then we just add on an extra
|
||||
// command and we'd need to flush the batch again.
|
||||
// This avoids that.
|
||||
if !exec_kind.is_isolated() && new_units != old_units && *path != ModulePath::Main {
|
||||
if new_units != old_units && *path != ModulePath::Main {
|
||||
self.engine
|
||||
.set_units(old_units.into(), Default::default(), exec_state.id_generator())
|
||||
.await?;
|
||||
}
|
||||
self.engine.replace_execution_kind(original_execution).await;
|
||||
|
||||
crate::log::log(format!("leave {path}"));
|
||||
|
||||
result.map(|result| (result, env_ref, local_state.module_exports))
|
||||
}
|
||||
|
||||
/// Execute an AST's program.
|
||||
#[async_recursion]
|
||||
pub(super) async fn preload_all_modules<'a>(
|
||||
&'a self,
|
||||
modules: &mut HashMap<String, Program>,
|
||||
program: NodeRef<'a, Program>,
|
||||
exec_state: &mut ExecState,
|
||||
) -> Result<(), KclError> {
|
||||
for statement in &program.body {
|
||||
if let BodyItem::ImportStatement(import_stmt) = statement {
|
||||
let path_str = import_stmt.path.to_string();
|
||||
|
||||
if modules.contains_key(&path_str) {
|
||||
// don't waste our time if we've already loaded the
|
||||
// module.
|
||||
continue;
|
||||
}
|
||||
|
||||
let source_range = SourceRange::from(import_stmt);
|
||||
let attrs = &import_stmt.outer_attrs;
|
||||
let module_id = self
|
||||
.open_module(&import_stmt.path, attrs, exec_state, source_range)
|
||||
.await?;
|
||||
|
||||
let Some(module) = exec_state.get_module(module_id) else {
|
||||
crate::log::log("we got back a module id that doesn't exist");
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
let progn = {
|
||||
// this dance is to avoid taking out a mut borrow
|
||||
// below on exec_state after borrowing here. As a
|
||||
// result, we need to clone (ugh) the program for
|
||||
// now.
|
||||
let ModuleRepr::Kcl(ref progn, _) = module.repr else {
|
||||
// not a kcl file, we can skip this
|
||||
continue;
|
||||
};
|
||||
progn.clone()
|
||||
};
|
||||
|
||||
modules.insert(path_str, progn.clone().inner);
|
||||
|
||||
self.preload_all_modules(modules, &progn, exec_state).await?;
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Execute an AST's program.
|
||||
#[async_recursion]
|
||||
pub(super) async fn exec_block<'a>(
|
||||
&'a self,
|
||||
program: NodeRef<'a, crate::parsing::ast::types::Program>,
|
||||
program: NodeRef<'a, Program>,
|
||||
exec_state: &mut ExecState,
|
||||
body_type: BodyType,
|
||||
) -> Result<Option<KclValue>, KclError> {
|
||||
@ -181,9 +224,9 @@ impl ExecutorContext {
|
||||
|
||||
match &import_stmt.selector {
|
||||
ImportSelector::List { items } => {
|
||||
let (env_ref, module_exports) = self
|
||||
.exec_module_for_items(module_id, exec_state, ExecutionKind::Isolated, source_range)
|
||||
.await?;
|
||||
println!("Importing items from module {}", import_stmt.path,);
|
||||
let (env_ref, module_exports) =
|
||||
self.exec_module_for_items(module_id, exec_state, source_range).await?;
|
||||
for import_item in items {
|
||||
// Extract the item from the module.
|
||||
let item = exec_state
|
||||
@ -224,9 +267,9 @@ impl ExecutorContext {
|
||||
}
|
||||
}
|
||||
ImportSelector::Glob(_) => {
|
||||
let (env_ref, module_exports) = self
|
||||
.exec_module_for_items(module_id, exec_state, ExecutionKind::Isolated, source_range)
|
||||
.await?;
|
||||
println!("Importing all items from module {}", import_stmt.path);
|
||||
let (env_ref, module_exports) =
|
||||
self.exec_module_for_items(module_id, exec_state, source_range).await?;
|
||||
for name in module_exports.iter() {
|
||||
let item = exec_state
|
||||
.stack()
|
||||
@ -417,7 +460,7 @@ impl ExecutorContext {
|
||||
Ok(last_expr)
|
||||
}
|
||||
|
||||
pub(super) async fn open_module(
|
||||
pub async fn open_module(
|
||||
&self,
|
||||
path: &ImportPath,
|
||||
attrs: &[Node<Annotation>],
|
||||
@ -425,6 +468,7 @@ impl ExecutorContext {
|
||||
source_range: SourceRange,
|
||||
) -> Result<ModuleId, KclError> {
|
||||
let resolved_path = ModulePath::from_import_path(path, &self.settings.project_directory);
|
||||
|
||||
match path {
|
||||
ImportPath::Kcl { .. } => {
|
||||
exec_state.global.mod_loader.cycle_check(&resolved_path, source_range)?;
|
||||
@ -481,7 +525,6 @@ impl ExecutorContext {
|
||||
&self,
|
||||
module_id: ModuleId,
|
||||
exec_state: &mut ExecState,
|
||||
exec_kind: ExecutionKind,
|
||||
source_range: SourceRange,
|
||||
) -> Result<(EnvironmentRef, Vec<String>), KclError> {
|
||||
let path = exec_state.global.module_infos[&module_id].path.clone();
|
||||
@ -492,7 +535,7 @@ impl ExecutorContext {
|
||||
ModuleRepr::Root => Err(exec_state.circular_import_error(&path, source_range)),
|
||||
ModuleRepr::Kcl(_, Some((env_ref, items))) => Ok((*env_ref, items.clone())),
|
||||
ModuleRepr::Kcl(program, cache) => self
|
||||
.exec_module_from_ast(program, module_id, &path, exec_state, exec_kind, source_range)
|
||||
.exec_module_from_ast(program, module_id, &path, exec_state, source_range)
|
||||
.await
|
||||
.map(|(_, er, items)| {
|
||||
*cache = Some((er, items.clone()));
|
||||
@ -514,7 +557,6 @@ impl ExecutorContext {
|
||||
module_id: ModuleId,
|
||||
module_name: &BoxNode<Name>,
|
||||
exec_state: &mut ExecState,
|
||||
exec_kind: ExecutionKind,
|
||||
source_range: SourceRange,
|
||||
) -> Result<Option<KclValue>, KclError> {
|
||||
exec_state.global.operations.push(Operation::GroupBegin {
|
||||
@ -533,7 +575,7 @@ impl ExecutorContext {
|
||||
ModuleRepr::Root => Err(exec_state.circular_import_error(&path, source_range)),
|
||||
ModuleRepr::Kcl(program, cached_items) => {
|
||||
let result = self
|
||||
.exec_module_from_ast(program, module_id, &path, exec_state, exec_kind, source_range)
|
||||
.exec_module_from_ast(program, module_id, &path, exec_state, source_range)
|
||||
.await;
|
||||
match result {
|
||||
Ok((val, env, items)) => {
|
||||
@ -556,19 +598,17 @@ impl ExecutorContext {
|
||||
result
|
||||
}
|
||||
|
||||
async fn exec_module_from_ast(
|
||||
pub async fn exec_module_from_ast(
|
||||
&self,
|
||||
program: &Node<Program>,
|
||||
module_id: ModuleId,
|
||||
path: &ModulePath,
|
||||
exec_state: &mut ExecState,
|
||||
exec_kind: ExecutionKind,
|
||||
source_range: SourceRange,
|
||||
) -> Result<(Option<KclValue>, EnvironmentRef, Vec<String>), KclError> {
|
||||
println!("exec_module_from_ast {path}");
|
||||
exec_state.global.mod_loader.enter_module(path);
|
||||
let result = self
|
||||
.exec_module_body(program, exec_state, exec_kind, false, module_id, path)
|
||||
.await;
|
||||
let result = self.exec_module_body(program, exec_state, false, module_id, path).await;
|
||||
exec_state.global.mod_loader.leave_module(path);
|
||||
|
||||
result.map_err(|err| {
|
||||
@ -604,7 +644,7 @@ impl ExecutorContext {
|
||||
Expr::Name(name) => {
|
||||
let value = name.get_result(exec_state, self).await?.clone();
|
||||
if let KclValue::Module { value: module_id, meta } = value {
|
||||
self.exec_module_for_result(module_id, name, exec_state, ExecutionKind::Normal, metadata.source_range)
|
||||
self.exec_module_for_result(module_id, name, exec_state, metadata.source_range)
|
||||
.await?
|
||||
.unwrap_or_else(|| {
|
||||
exec_state.warn(CompilationError::err(
|
||||
@ -792,7 +832,7 @@ impl Node<Name> {
|
||||
};
|
||||
|
||||
mem_spec = Some(
|
||||
ctx.exec_module_for_items(*module_id, exec_state, ExecutionKind::Normal, p.as_source_range())
|
||||
ctx.exec_module_for_items(*module_id, exec_state, p.as_source_range())
|
||||
.await?,
|
||||
);
|
||||
}
|
||||
@ -1273,7 +1313,7 @@ impl Node<CallExpressionKw> {
|
||||
));
|
||||
}
|
||||
|
||||
let op = if func.feature_tree_operation() && !ctx.is_isolated_execution().await {
|
||||
let op = if func.feature_tree_operation() {
|
||||
let op_labeled_args = args
|
||||
.kw_args
|
||||
.labeled
|
||||
@ -1359,7 +1399,7 @@ impl Node<CallExpressionKw> {
|
||||
e.add_source_ranges(vec![callsite])
|
||||
})?;
|
||||
|
||||
if matches!(fn_src, FunctionSource::User { .. }) && !ctx.is_isolated_execution().await {
|
||||
if matches!(fn_src, FunctionSource::User { .. }) {
|
||||
// Track return operation.
|
||||
exec_state.global.operations.push(Operation::GroupEnd);
|
||||
}
|
||||
@ -1411,7 +1451,7 @@ impl Node<CallExpression> {
|
||||
));
|
||||
}
|
||||
|
||||
let op = if func.feature_tree_operation() && !ctx.is_isolated_execution().await {
|
||||
let op = if func.feature_tree_operation() {
|
||||
let op_labeled_args = func
|
||||
.args(false)
|
||||
.iter()
|
||||
@ -1469,19 +1509,17 @@ impl Node<CallExpression> {
|
||||
// exec_state.
|
||||
let func = fn_name.get_result(exec_state, ctx).await?.clone();
|
||||
|
||||
if !ctx.is_isolated_execution().await {
|
||||
// Track call operation.
|
||||
exec_state.global.operations.push(Operation::GroupBegin {
|
||||
group: Group::FunctionCall {
|
||||
name: Some(fn_name.to_string()),
|
||||
function_source_range: func.function_def_source_range().unwrap_or_default(),
|
||||
unlabeled_arg: None,
|
||||
// TODO: Add the arguments for legacy positional parameters.
|
||||
labeled_args: Default::default(),
|
||||
},
|
||||
source_range: callsite,
|
||||
});
|
||||
}
|
||||
// Track call operation.
|
||||
exec_state.global.operations.push(Operation::GroupBegin {
|
||||
group: Group::FunctionCall {
|
||||
name: Some(fn_name.to_string()),
|
||||
function_source_range: func.function_def_source_range().unwrap_or_default(),
|
||||
unlabeled_arg: None,
|
||||
// TODO: Add the arguments for legacy positional parameters.
|
||||
labeled_args: Default::default(),
|
||||
},
|
||||
source_range: callsite,
|
||||
});
|
||||
|
||||
let Some(fn_src) = func.as_fn() else {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
@ -1510,10 +1548,8 @@ impl Node<CallExpression> {
|
||||
})
|
||||
})?;
|
||||
|
||||
if !ctx.is_isolated_execution().await {
|
||||
// Track return operation.
|
||||
exec_state.global.operations.push(Operation::GroupEnd);
|
||||
}
|
||||
// Track return operation.
|
||||
exec_state.global.operations.push(Operation::GroupEnd);
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
@ -2241,7 +2277,7 @@ impl FunctionSource {
|
||||
}
|
||||
}
|
||||
|
||||
let op = if props.include_in_feature_tree && !ctx.is_isolated_execution().await {
|
||||
let op = if props.include_in_feature_tree {
|
||||
let op_labeled_args = args
|
||||
.kw_args
|
||||
.labeled
|
||||
@ -2285,28 +2321,26 @@ impl FunctionSource {
|
||||
Ok(Some(result))
|
||||
}
|
||||
FunctionSource::User { ast, memory, .. } => {
|
||||
if !ctx.is_isolated_execution().await {
|
||||
// Track call operation.
|
||||
let op_labeled_args = args
|
||||
.kw_args
|
||||
.labeled
|
||||
.iter()
|
||||
.map(|(k, arg)| (k.clone(), OpArg::new(OpKclValue::from(&arg.value), arg.source_range)))
|
||||
.collect();
|
||||
exec_state.global.operations.push(Operation::GroupBegin {
|
||||
group: Group::FunctionCall {
|
||||
name: fn_name,
|
||||
function_source_range: ast.as_source_range(),
|
||||
unlabeled_arg: args
|
||||
.kw_args
|
||||
.unlabeled
|
||||
.as_ref()
|
||||
.map(|arg| OpArg::new(OpKclValue::from(&arg.value), arg.source_range)),
|
||||
labeled_args: op_labeled_args,
|
||||
},
|
||||
source_range: callsite,
|
||||
});
|
||||
}
|
||||
// Track call operation.
|
||||
let op_labeled_args = args
|
||||
.kw_args
|
||||
.labeled
|
||||
.iter()
|
||||
.map(|(k, arg)| (k.clone(), OpArg::new(OpKclValue::from(&arg.value), arg.source_range)))
|
||||
.collect();
|
||||
exec_state.global.operations.push(Operation::GroupBegin {
|
||||
group: Group::FunctionCall {
|
||||
name: fn_name,
|
||||
function_source_range: ast.as_source_range(),
|
||||
unlabeled_arg: args
|
||||
.kw_args
|
||||
.unlabeled
|
||||
.as_ref()
|
||||
.map(|arg| OpArg::new(OpKclValue::from(&arg.value), arg.source_range)),
|
||||
labeled_args: op_labeled_args,
|
||||
},
|
||||
source_range: callsite,
|
||||
});
|
||||
|
||||
call_user_defined_function_kw(args.kw_args, *memory, ast, exec_state, ctx).await
|
||||
}
|
||||
@ -2317,13 +2351,14 @@ impl FunctionSource {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::*;
|
||||
use crate::{
|
||||
execution::{memory::Stack, parse_execute, ContextType},
|
||||
parsing::ast::types::{DefaultParamVal, Identifier, Parameter},
|
||||
ExecutorSettings,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn test_assign_args_to_params() {
|
||||
@ -2432,7 +2467,7 @@ mod test {
|
||||
// Run each test.
|
||||
let func_expr = &Node::no_src(FunctionExpression {
|
||||
params,
|
||||
body: crate::parsing::ast::types::Program::empty(),
|
||||
body: Program::empty(),
|
||||
return_type: None,
|
||||
digest: None,
|
||||
});
|
||||
@ -2534,4 +2569,100 @@ a = foo()
|
||||
let result = parse_execute(program).await;
|
||||
assert!(result.unwrap_err().to_string().contains("return"));
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn load_all_modules() {
|
||||
// program a.kcl
|
||||
let programa_kcl = r#"
|
||||
export a = 1
|
||||
"#;
|
||||
// program b.kcl
|
||||
let programb_kcl = r#"
|
||||
import a from 'a.kcl'
|
||||
|
||||
export b = a + 1
|
||||
"#;
|
||||
// program c.kcl
|
||||
let programc_kcl = r#"
|
||||
import a from 'a.kcl'
|
||||
|
||||
export c = a + 2
|
||||
"#;
|
||||
|
||||
// program main.kcl
|
||||
let main_kcl = r#"
|
||||
import b from 'b.kcl'
|
||||
import c from 'c.kcl'
|
||||
|
||||
d = b + c
|
||||
"#;
|
||||
|
||||
let main = crate::parsing::parse_str(main_kcl, ModuleId::default())
|
||||
.parse_errs_as_err()
|
||||
.unwrap();
|
||||
|
||||
let tmpdir = tempdir::TempDir::new("zma_kcl_load_all_modules").unwrap();
|
||||
|
||||
tokio::fs::File::create(tmpdir.path().join("main.kcl"))
|
||||
.await
|
||||
.unwrap()
|
||||
.write_all(main_kcl.as_bytes())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
tokio::fs::File::create(tmpdir.path().join("a.kcl"))
|
||||
.await
|
||||
.unwrap()
|
||||
.write_all(programa_kcl.as_bytes())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
tokio::fs::File::create(tmpdir.path().join("b.kcl"))
|
||||
.await
|
||||
.unwrap()
|
||||
.write_all(programb_kcl.as_bytes())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
tokio::fs::File::create(tmpdir.path().join("c.kcl"))
|
||||
.await
|
||||
.unwrap()
|
||||
.write_all(programc_kcl.as_bytes())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
let exec_ctxt = ExecutorContext {
|
||||
engine: Arc::new(Box::new(
|
||||
crate::engine::conn_mock::EngineConnection::new()
|
||||
.await
|
||||
.map_err(|err| {
|
||||
KclError::Internal(crate::errors::KclErrorDetails {
|
||||
message: format!("Failed to create mock engine connection: {}", err),
|
||||
source_ranges: vec![SourceRange::default()],
|
||||
})
|
||||
})
|
||||
.unwrap(),
|
||||
)),
|
||||
fs: Arc::new(crate::fs::FileManager::new()),
|
||||
settings: ExecutorSettings {
|
||||
project_directory: Some(tmpdir.path().into()),
|
||||
..Default::default()
|
||||
},
|
||||
stdlib: Arc::new(crate::std::StdLib::new()),
|
||||
context_type: ContextType::Mock,
|
||||
};
|
||||
let mut exec_state = ExecState::new(&exec_ctxt);
|
||||
|
||||
exec_ctxt
|
||||
.run_concurrent(
|
||||
&crate::Program {
|
||||
ast: main.clone(),
|
||||
original_file_contents: "".to_owned(),
|
||||
},
|
||||
&mut exec_state,
|
||||
false,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
@ -418,6 +418,9 @@ pub struct Sketch {
|
||||
pub artifact_id: ArtifactId,
|
||||
#[ts(skip)]
|
||||
pub original_id: uuid::Uuid,
|
||||
/// If the sketch includes a mirror.
|
||||
#[serde(skip)]
|
||||
pub mirror: Option<uuid::Uuid>,
|
||||
pub units: UnitLen,
|
||||
/// Metadata.
|
||||
#[serde(skip)]
|
||||
|
@ -27,21 +27,22 @@ pub use memory::EnvironmentRef;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
pub use state::{ExecState, MetaSettings};
|
||||
use tokio::task::JoinSet;
|
||||
|
||||
use crate::{
|
||||
engine::EngineManager,
|
||||
errors::KclError,
|
||||
errors::{KclError, KclErrorDetails},
|
||||
execution::{
|
||||
artifact::build_artifact_graph,
|
||||
cache::{CacheInformation, CacheResult},
|
||||
types::{UnitAngle, UnitLen},
|
||||
},
|
||||
fs::FileManager,
|
||||
modules::{ModuleId, ModulePath},
|
||||
modules::{ModuleId, ModulePath, ModuleRepr},
|
||||
parsing::ast::types::{Expr, ImportPath, NodeRef},
|
||||
source_range::SourceRange,
|
||||
std::StdLib,
|
||||
CompilationError, ExecError, ExecutionKind, KclErrorWithOutputs,
|
||||
CompilationError, ExecError, KclErrorWithOutputs,
|
||||
};
|
||||
|
||||
pub(crate) mod annotations;
|
||||
@ -497,13 +498,9 @@ impl ExecutorContext {
|
||||
self.context_type == ContextType::Mock || self.context_type == ContextType::MockCustomForwarded
|
||||
}
|
||||
|
||||
pub async fn is_isolated_execution(&self) -> bool {
|
||||
self.engine.execution_kind().await.is_isolated()
|
||||
}
|
||||
|
||||
/// Returns true if we should not send engine commands for any reason.
|
||||
pub async fn no_engine_commands(&self) -> bool {
|
||||
self.is_mock() || self.is_isolated_execution().await
|
||||
self.is_mock()
|
||||
}
|
||||
|
||||
pub async fn send_clear_scene(
|
||||
@ -674,7 +671,7 @@ impl ExecutorContext {
|
||||
(program, exec_state, false)
|
||||
};
|
||||
|
||||
let result = self.inner_run(&program, &mut exec_state, preserve_mem).await;
|
||||
let result = self.run_concurrent(&program, &mut exec_state, preserve_mem).await;
|
||||
|
||||
if result.is_err() {
|
||||
cache::bust_cache().await;
|
||||
@ -707,7 +704,124 @@ impl ExecutorContext {
|
||||
program: &crate::Program,
|
||||
exec_state: &mut ExecState,
|
||||
) -> Result<(EnvironmentRef, Option<ModelingSessionData>), KclErrorWithOutputs> {
|
||||
self.inner_run(program, exec_state, false).await
|
||||
self.run_concurrent(program, exec_state, false).await
|
||||
}
|
||||
|
||||
/// Perform the execution of a program using an (experimental!) concurrent
|
||||
/// execution model. This has the same signature as [Self::run].
|
||||
///
|
||||
/// For now -- do not use this unless you're willing to accept some
|
||||
/// breakage.
|
||||
///
|
||||
/// You can optionally pass in some initialization memory for partial
|
||||
/// execution.
|
||||
///
|
||||
/// To access non-fatal errors and warnings, extract them from the `ExecState`.
|
||||
pub async fn run_concurrent(
|
||||
&self,
|
||||
program: &crate::Program,
|
||||
exec_state: &mut ExecState,
|
||||
preserve_mem: bool,
|
||||
) -> Result<(EnvironmentRef, Option<ModelingSessionData>), KclErrorWithOutputs> {
|
||||
self.prepare_mem(exec_state).await.unwrap();
|
||||
|
||||
let mut universe = std::collections::HashMap::new();
|
||||
let mut out_id_map = std::collections::HashMap::new();
|
||||
|
||||
crate::walk::import_universe(self, &program.ast, &mut universe, &mut out_id_map, exec_state)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
for modules in crate::walk::import_graph(&universe).unwrap().into_iter() {
|
||||
println!("Running module {modules:?}");
|
||||
//let mut set = JoinSet::new();
|
||||
println!("AFTER Running module {modules:?}");
|
||||
let (results_tx, mut results_rx): (
|
||||
tokio::sync::mpsc::Sender<(
|
||||
String,
|
||||
Result<(Option<KclValue>, EnvironmentRef, Vec<String>), KclError>,
|
||||
)>,
|
||||
tokio::sync::mpsc::Receiver<_>,
|
||||
) = tokio::sync::mpsc::channel(1);
|
||||
|
||||
for module in modules {
|
||||
let program = universe.get(&module).unwrap().clone();
|
||||
let Some(module_id) = out_id_map.get(&module) else {
|
||||
panic!("Module {module} not found in exec_state");
|
||||
};
|
||||
let module_id = module_id.clone();
|
||||
let module_path = {
|
||||
let module_info = exec_state.get_module(module_id).unwrap();
|
||||
let module_path = module_info.path.clone();
|
||||
module_path
|
||||
};
|
||||
let exec_state = exec_state.clone();
|
||||
let exec_ctxt = self.clone();
|
||||
let results_tx = results_tx.clone();
|
||||
|
||||
println!("before spawn");
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
{
|
||||
wasm_bindgen_futures::spawn_local(async move {
|
||||
//set.spawn(async move {
|
||||
println!("Running module {module} from run_concurrent");
|
||||
let mut exec_state = exec_state;
|
||||
let exec_ctxt = exec_ctxt;
|
||||
let program = program;
|
||||
|
||||
let result = exec_ctxt
|
||||
.exec_module_from_ast(
|
||||
&program,
|
||||
module_id,
|
||||
&module_path,
|
||||
&mut exec_state,
|
||||
Default::default(),
|
||||
)
|
||||
.await;
|
||||
|
||||
results_tx.send((module, result)).await.unwrap();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
drop(results_tx);
|
||||
|
||||
while let Some((module, result)) = results_rx.recv().await {
|
||||
match result {
|
||||
Ok((env_ref, session_data, variables)) => {
|
||||
println!("{module} {:?}", variables);
|
||||
let Some(module_id) = out_id_map.get(&module) else {
|
||||
//let snapshot_png_bytes = self.prepare_snapshot().await.unwrap().contents.0;
|
||||
// Save to a file.
|
||||
//tokio::fs::write("snapshot.png", snapshot_png_bytes).await.unwrap();
|
||||
|
||||
return Err(KclErrorWithOutputs::no_outputs(KclError::Internal(KclErrorDetails {
|
||||
message: format!("Module {module} not found in exec_state"),
|
||||
source_ranges: Default::default(),
|
||||
})));
|
||||
};
|
||||
let path = exec_state.global.module_infos[module_id].path.clone();
|
||||
let mut repr = exec_state.global.module_infos[module_id].take_repr();
|
||||
|
||||
let ModuleRepr::Kcl(program, cache) = &mut repr else {
|
||||
continue;
|
||||
};
|
||||
|
||||
*cache = Some((session_data, variables.clone()));
|
||||
|
||||
exec_state.global.module_infos[module_id].restore_repr(repr);
|
||||
}
|
||||
Err(e) => {
|
||||
//let snapshot_png_bytes = self.prepare_snapshot().await.unwrap().contents.0;
|
||||
// Save to a file.
|
||||
//tokio::fs::write("snapshot.png", snapshot_png_bytes).await.unwrap();
|
||||
return Err(KclErrorWithOutputs::no_outputs(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.inner_run(program, exec_state, preserve_mem).await
|
||||
}
|
||||
|
||||
/// Perform the execution of a program. Accept all possible parameters and
|
||||
@ -758,11 +872,11 @@ impl ExecutorContext {
|
||||
)
|
||||
})?;
|
||||
|
||||
if !self.is_mock() {
|
||||
/* if !self.is_mock() {
|
||||
let mut mem = exec_state.stack().deep_clone();
|
||||
mem.restore_env(env_ref);
|
||||
cache::write_old_memory((mem, exec_state.global.module_infos.clone())).await;
|
||||
}
|
||||
}*/
|
||||
let session_data = self.engine.get_session_data().await;
|
||||
Ok((env_ref, session_data))
|
||||
}
|
||||
@ -785,7 +899,6 @@ impl ExecutorContext {
|
||||
.exec_module_body(
|
||||
program,
|
||||
exec_state,
|
||||
ExecutionKind::Normal,
|
||||
preserve_mem,
|
||||
ModuleId::default(),
|
||||
&ModulePath::Main,
|
||||
@ -839,9 +952,7 @@ impl ExecutorContext {
|
||||
source_range,
|
||||
)
|
||||
.await?;
|
||||
let (module_memory, _) = self
|
||||
.exec_module_for_items(id, exec_state, ExecutionKind::Isolated, source_range)
|
||||
.await?;
|
||||
let (module_memory, _) = self.exec_module_for_items(id, exec_state, source_range).await?;
|
||||
|
||||
exec_state.mut_stack().memory.set_std(module_memory);
|
||||
}
|
||||
|
@ -228,6 +228,10 @@ impl ExecState {
|
||||
self.global.module_infos.insert(id, module_info);
|
||||
}
|
||||
|
||||
pub fn get_module(&mut self, id: ModuleId) -> Option<&ModuleInfo> {
|
||||
self.global.module_infos.get(&id)
|
||||
}
|
||||
|
||||
pub fn length_unit(&self) -> UnitLen {
|
||||
self.mod_local.settings.default_length_units
|
||||
}
|
||||
|
@ -76,12 +76,12 @@ pub mod std;
|
||||
pub mod test_server;
|
||||
mod thread;
|
||||
mod unparser;
|
||||
mod walk;
|
||||
pub mod walk;
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
mod wasm;
|
||||
|
||||
pub use coredump::CoreDump;
|
||||
pub use engine::{EngineManager, EngineStats, ExecutionKind};
|
||||
pub use engine::{EngineManager, EngineStats};
|
||||
pub use errors::{
|
||||
CompilationError, ConnectionError, ExecError, KclError, KclErrorWithOutputs, Report, ReportWithOutputs,
|
||||
};
|
||||
|
@ -13,7 +13,7 @@ use kcmc::{
|
||||
websocket::{ModelingCmdReq, OkWebSocketResponseData},
|
||||
ModelingCmd,
|
||||
};
|
||||
use kittycad_modeling_cmds as kcmc;
|
||||
use kittycad_modeling_cmds::{self as kcmc};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::{
|
||||
@ -168,13 +168,18 @@ pub(crate) async fn do_post_extrude<'a>(
|
||||
)
|
||||
.await?;
|
||||
|
||||
// The "get extrusion face info" API call requires *any* edge on the sketch being extruded.
|
||||
// So, let's just use the first one.
|
||||
let Some(any_edge_id) = sketch.paths.first().map(|edge| edge.get_base().geo_meta.id) else {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: "Expected a non-empty sketch".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
let any_edge_id = if let Some(edge_id) = sketch.mirror {
|
||||
edge_id
|
||||
} else {
|
||||
// The "get extrusion face info" API call requires *any* edge on the sketch being extruded.
|
||||
// So, let's just use the first one.
|
||||
let Some(any_edge_id) = sketch.paths.first().map(|edge| edge.get_base().geo_meta.id) else {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: "Expected a non-empty sketch".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
};
|
||||
any_edge_id
|
||||
};
|
||||
|
||||
let mut sketch = sketch.clone();
|
||||
|
@ -2,10 +2,13 @@
|
||||
|
||||
use anyhow::Result;
|
||||
use kcmc::{each_cmd as mcmd, ModelingCmd};
|
||||
use kittycad_modeling_cmds::{self as kcmc, length_unit::LengthUnit, shared::Point3d};
|
||||
use kittycad_modeling_cmds::{
|
||||
self as kcmc, length_unit::LengthUnit, ok_response::OkModelingCmdResponse, output::EntityGetAllChildUuids,
|
||||
shared::Point3d, websocket::OkWebSocketResponseData,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
errors::KclError,
|
||||
errors::{KclError, KclErrorDetails},
|
||||
execution::{
|
||||
types::{PrimitiveType, RuntimeType},
|
||||
ExecState, KclValue, Sketch,
|
||||
@ -31,13 +34,21 @@ pub async fn mirror_2d(exec_state: &mut ExecState, args: Args) -> Result<KclValu
|
||||
Ok(sketches.into())
|
||||
}
|
||||
|
||||
/// Mirror a sketch.
|
||||
///
|
||||
/// Only works on unclosed sketches for now.
|
||||
async fn inner_mirror_2d(
|
||||
sketches: Vec<Sketch>,
|
||||
axis: Axis2dOrEdgeReference,
|
||||
exec_state: &mut ExecState,
|
||||
args: Args,
|
||||
) -> Result<Vec<Sketch>, KclError> {
|
||||
let starting_sketches = sketches;
|
||||
let mut starting_sketches = sketches.clone();
|
||||
|
||||
// Update all to have a mirror.
|
||||
starting_sketches.iter_mut().for_each(|sketch| {
|
||||
sketch.mirror = Some(exec_state.next_uuid());
|
||||
});
|
||||
|
||||
if args.ctx.no_engine_commands().await {
|
||||
return Ok(starting_sketches);
|
||||
@ -77,5 +88,40 @@ async fn inner_mirror_2d(
|
||||
}
|
||||
};
|
||||
|
||||
// After the mirror, get the first child uuid for the path.
|
||||
// The "get extrusion face info" API call requires *any* edge on the sketch being extruded.
|
||||
// But if you mirror2d a sketch these IDs might change so we need to get the children versus
|
||||
// using the IDs we already have.
|
||||
// We only do this with mirrors because otherwise it is a waste of a websocket call.
|
||||
for sketch in &mut starting_sketches {
|
||||
let response = args
|
||||
.send_modeling_cmd(
|
||||
exec_state.next_uuid(),
|
||||
ModelingCmd::from(mcmd::EntityGetAllChildUuids { entity_id: sketch.id }),
|
||||
)
|
||||
.await?;
|
||||
let OkWebSocketResponseData::Modeling {
|
||||
modeling_response:
|
||||
OkModelingCmdResponse::EntityGetAllChildUuids(EntityGetAllChildUuids { entity_ids: child_ids }),
|
||||
} = response
|
||||
else {
|
||||
return Err(KclError::Internal(KclErrorDetails {
|
||||
message: "Expected a successful response from EntityGetAllChildUuids".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
};
|
||||
|
||||
if child_ids.len() >= 2 {
|
||||
// The first child is the original sketch, the second is the mirrored sketch.
|
||||
let child_id = child_ids[1];
|
||||
sketch.mirror = Some(child_id);
|
||||
} else {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: "Expected child uuids to be >= 2".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(starting_sketches)
|
||||
}
|
||||
|
@ -1343,6 +1343,7 @@ pub(crate) async fn inner_start_profile_at(
|
||||
on: sketch_surface.clone(),
|
||||
paths: vec![],
|
||||
units: sketch_surface.units(),
|
||||
mirror: Default::default(),
|
||||
meta: vec![args.source_range.into()],
|
||||
tags: if let Some(tag) = &tag {
|
||||
let mut tag_identifier: TagIdentifier = tag.into();
|
||||
|
@ -6,8 +6,10 @@ use std::{
|
||||
use anyhow::Result;
|
||||
|
||||
use crate::{
|
||||
parsing::ast::types::{ImportPath, NodeRef, Program},
|
||||
modules::ModuleRepr,
|
||||
parsing::ast::types::{ImportPath, Node as AstNode, NodeRef, Program},
|
||||
walk::{Node, Visitable},
|
||||
ExecState, ExecutorContext, ModuleId,
|
||||
};
|
||||
|
||||
/// Specific dependency between two modules. The 0th element of this tuple
|
||||
@ -23,7 +25,7 @@ type Graph = Vec<Dependency>;
|
||||
/// run concurrently. Each "stage" is blocking in this model, which will
|
||||
/// change in the future. Don't use this function widely, yet.
|
||||
#[allow(clippy::iter_over_hash_type)]
|
||||
pub fn import_graph(progs: HashMap<String, NodeRef<'_, Program>>) -> Result<Vec<Vec<String>>> {
|
||||
pub fn import_graph(progs: &HashMap<String, AstNode<Program>>) -> Result<Vec<Vec<String>>> {
|
||||
let mut graph = Graph::new();
|
||||
|
||||
for (name, program) in progs.iter() {
|
||||
@ -41,6 +43,9 @@ pub fn import_graph(progs: HashMap<String, NodeRef<'_, Program>>) -> Result<Vec<
|
||||
|
||||
#[allow(clippy::iter_over_hash_type)]
|
||||
fn topsort(all_modules: &[&str], graph: Graph) -> Result<Vec<Vec<String>>> {
|
||||
if all_modules.is_empty() {
|
||||
return Ok(vec![]);
|
||||
}
|
||||
let mut dep_map = HashMap::<String, Vec<String>>::new();
|
||||
|
||||
for (dependent, dependency) in graph.iter() {
|
||||
@ -57,6 +62,7 @@ fn topsort(all_modules: &[&str], graph: Graph) -> Result<Vec<Vec<String>>> {
|
||||
let mut order = vec![];
|
||||
|
||||
loop {
|
||||
println!("waiting_modules: {:?}", waiting_modules);
|
||||
// Each pass through we need to find any modules which have nothing
|
||||
// "pointing at it" -- so-called reverse dependencies. This is an entry
|
||||
// that is either not in the dep_map OR an empty list.
|
||||
@ -101,7 +107,7 @@ fn topsort(all_modules: &[&str], graph: Graph) -> Result<Vec<Vec<String>>> {
|
||||
Ok(order)
|
||||
}
|
||||
|
||||
pub(crate) fn import_dependencies(prog: NodeRef<'_, Program>) -> Result<Vec<String>> {
|
||||
pub(crate) fn import_dependencies(prog: NodeRef<Program>) -> Result<Vec<String>> {
|
||||
let ret = Arc::new(Mutex::new(vec![]));
|
||||
|
||||
fn walk(ret: Arc<Mutex<Vec<String>>>, node: Node<'_>) {
|
||||
@ -125,6 +131,51 @@ pub(crate) fn import_dependencies(prog: NodeRef<'_, Program>) -> Result<Vec<Stri
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
pub(crate) async fn import_universe<'prog>(
|
||||
ctx: &ExecutorContext,
|
||||
prog: NodeRef<'prog, Program>,
|
||||
out: &mut HashMap<String, AstNode<Program>>,
|
||||
out_id_map: &mut HashMap<String, ModuleId>,
|
||||
exec_state: &mut ExecState,
|
||||
) -> Result<()> {
|
||||
let modules = import_dependencies(prog)?;
|
||||
for module in modules {
|
||||
eprintln!("{:?}", module);
|
||||
|
||||
if out.contains_key(&module) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let module_id = ctx
|
||||
.open_module(
|
||||
&ImportPath::Kcl {
|
||||
filename: module.to_string(),
|
||||
},
|
||||
&[],
|
||||
exec_state,
|
||||
Default::default(),
|
||||
)
|
||||
.await?;
|
||||
out_id_map.insert(module.clone(), module_id);
|
||||
|
||||
let program = {
|
||||
let Some(module_info) = exec_state.get_module(module_id) else {
|
||||
// We should never get here we just fucking added it.
|
||||
anyhow::bail!("Module {} not found", module);
|
||||
};
|
||||
let ModuleRepr::Kcl(program, _) = &module_info.repr else {
|
||||
anyhow::bail!("Module {} is not a KCL program", module);
|
||||
};
|
||||
program.clone()
|
||||
};
|
||||
|
||||
out.insert(module.clone(), program.clone());
|
||||
Box::pin(import_universe(ctx, &program, out, out_id_map, exec_state)).await?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@ -140,16 +191,16 @@ mod tests {
|
||||
let mut modules = HashMap::new();
|
||||
|
||||
let a = kcl!("");
|
||||
modules.insert("a.kcl".to_owned(), &a);
|
||||
modules.insert("a.kcl".to_owned(), a);
|
||||
|
||||
let b = kcl!(
|
||||
"
|
||||
import \"a.kcl\"
|
||||
"
|
||||
);
|
||||
modules.insert("b.kcl".to_owned(), &b);
|
||||
modules.insert("b.kcl".to_owned(), b);
|
||||
|
||||
let order = import_graph(modules).unwrap();
|
||||
let order = import_graph(&modules).unwrap();
|
||||
assert_eq!(vec![vec!["a.kcl".to_owned()], vec!["b.kcl".to_owned()]], order);
|
||||
}
|
||||
|
||||
@ -162,16 +213,16 @@ import \"a.kcl\"
|
||||
y = 2
|
||||
"
|
||||
);
|
||||
modules.insert("a.kcl".to_owned(), &a);
|
||||
modules.insert("a.kcl".to_owned(), a);
|
||||
|
||||
let b = kcl!(
|
||||
"
|
||||
x = 1
|
||||
"
|
||||
);
|
||||
modules.insert("b.kcl".to_owned(), &b);
|
||||
modules.insert("b.kcl".to_owned(), b);
|
||||
|
||||
let order = import_graph(modules).unwrap();
|
||||
let order = import_graph(&modules).unwrap();
|
||||
assert_eq!(vec![vec!["a.kcl".to_owned(), "b.kcl".to_owned()]], order);
|
||||
}
|
||||
|
||||
@ -180,23 +231,23 @@ x = 1
|
||||
let mut modules = HashMap::new();
|
||||
|
||||
let a = kcl!("");
|
||||
modules.insert("a.kcl".to_owned(), &a);
|
||||
modules.insert("a.kcl".to_owned(), a);
|
||||
|
||||
let b = kcl!(
|
||||
"
|
||||
import \"a.kcl\"
|
||||
"
|
||||
);
|
||||
modules.insert("b.kcl".to_owned(), &b);
|
||||
modules.insert("b.kcl".to_owned(), b);
|
||||
|
||||
let c = kcl!(
|
||||
"
|
||||
import \"a.kcl\"
|
||||
"
|
||||
);
|
||||
modules.insert("c.kcl".to_owned(), &c);
|
||||
modules.insert("c.kcl".to_owned(), c);
|
||||
|
||||
let order = import_graph(modules).unwrap();
|
||||
let order = import_graph(&modules).unwrap();
|
||||
assert_eq!(
|
||||
vec![vec!["a.kcl".to_owned()], vec!["b.kcl".to_owned(), "c.kcl".to_owned()]],
|
||||
order
|
||||
@ -212,15 +263,15 @@ import \"a.kcl\"
|
||||
import \"b.kcl\"
|
||||
"
|
||||
);
|
||||
modules.insert("a.kcl".to_owned(), &a);
|
||||
modules.insert("a.kcl".to_owned(), a);
|
||||
|
||||
let b = kcl!(
|
||||
"
|
||||
import \"a.kcl\"
|
||||
"
|
||||
);
|
||||
modules.insert("b.kcl".to_owned(), &b);
|
||||
modules.insert("b.kcl".to_owned(), b);
|
||||
|
||||
import_graph(modules).unwrap_err();
|
||||
import_graph(&modules).unwrap_err();
|
||||
}
|
||||
}
|
||||
|
@ -8,3 +8,5 @@ mod import_graph;
|
||||
pub use ast_node::Node;
|
||||
pub use ast_visitor::Visitable;
|
||||
pub use ast_walk::walk;
|
||||
pub use import_graph::import_graph;
|
||||
pub(crate) use import_graph::import_universe;
|
||||
|
@ -96,6 +96,25 @@ export fn circle(
|
||||
///
|
||||
/// example = extrude(sketch001, length = 10)
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// // Sketch on the face of a mirrored sketch, that has been extruded.
|
||||
/// sketch0011 = startSketchOn(XY)
|
||||
/// |> startProfileAt([6.77, 0], %)
|
||||
/// |> yLine(length = 1.27)
|
||||
/// |> tangentialArcTo([5.96, 2.37], %)
|
||||
/// |> tangentialArcTo([-6.2, 2.44], %)
|
||||
/// |> tangentialArcTo([-6.6, 1.82], %)
|
||||
/// |> yLine(length = -1.82)
|
||||
/// |> mirror2d( axis = X )
|
||||
/// |> extrude(length = 10)
|
||||
///
|
||||
/// sketch002 = startSketchOn(sketch0011, 'END')
|
||||
/// |> circle( center = [-0.01, 1.58], radius = 1.2 )
|
||||
/// |> extrude(length = 1.2)
|
||||
///
|
||||
/// shell([sketch002], faces = ['end'], thickness = .1 )
|
||||
/// ```
|
||||
@(impl = std_rust)
|
||||
export fn mirror2d(
|
||||
/// The sketch or sketches to be reflected.
|
||||
|
@ -209,6 +209,14 @@ description: Artifact commands i-beam.kcl
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "entity_get_all_child_uuids",
|
||||
"entity_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
@ -229,6 +237,14 @@ description: Artifact commands i-beam.kcl
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "entity_get_all_child_uuids",
|
||||
"entity_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
@ -278,5 +294,345 @@ description: Artifact commands i-beam.kcl
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "solid3d_get_opposite_edge",
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]",
|
||||
"face_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "solid3d_get_next_adjacent_edge",
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]",
|
||||
"face_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "solid3d_get_opposite_edge",
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]",
|
||||
"face_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "solid3d_get_next_adjacent_edge",
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]",
|
||||
"face_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "solid3d_get_opposite_edge",
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]",
|
||||
"face_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "solid3d_get_next_adjacent_edge",
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]",
|
||||
"face_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "solid3d_get_opposite_edge",
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]",
|
||||
"face_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "solid3d_get_next_adjacent_edge",
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]",
|
||||
"face_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "solid3d_get_opposite_edge",
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]",
|
||||
"face_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "solid3d_get_next_adjacent_edge",
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]",
|
||||
"face_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "solid3d_get_opposite_edge",
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]",
|
||||
"face_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "solid3d_get_next_adjacent_edge",
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]",
|
||||
"face_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "solid3d_get_opposite_edge",
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]",
|
||||
"face_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "solid3d_get_next_adjacent_edge",
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]",
|
||||
"face_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "solid3d_get_opposite_edge",
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]",
|
||||
"face_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "solid3d_get_next_adjacent_edge",
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]",
|
||||
"face_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "solid3d_get_opposite_edge",
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]",
|
||||
"face_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "solid3d_get_next_adjacent_edge",
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]",
|
||||
"face_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "solid3d_get_opposite_edge",
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]",
|
||||
"face_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "solid3d_get_next_adjacent_edge",
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]",
|
||||
"face_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "solid3d_get_opposite_edge",
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]",
|
||||
"face_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "solid3d_get_next_adjacent_edge",
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]",
|
||||
"face_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "solid3d_get_opposite_edge",
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]",
|
||||
"face_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "solid3d_get_next_adjacent_edge",
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]",
|
||||
"face_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "solid3d_get_opposite_edge",
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]",
|
||||
"face_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "solid3d_get_next_adjacent_edge",
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]",
|
||||
"face_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "solid3d_get_opposite_edge",
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]",
|
||||
"face_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "solid3d_get_next_adjacent_edge",
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]",
|
||||
"face_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "solid3d_get_opposite_edge",
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]",
|
||||
"face_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "solid3d_get_next_adjacent_edge",
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]",
|
||||
"face_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "solid3d_get_opposite_edge",
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]",
|
||||
"face_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "solid3d_get_next_adjacent_edge",
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]",
|
||||
"face_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "solid3d_get_opposite_edge",
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]",
|
||||
"face_id": "[uuid]"
|
||||
}
|
||||
},
|
||||
{
|
||||
"cmdId": "[uuid]",
|
||||
"range": [],
|
||||
"command": {
|
||||
"type": "solid3d_get_next_adjacent_edge",
|
||||
"object_id": "[uuid]",
|
||||
"edge_id": "[uuid]",
|
||||
"face_id": "[uuid]"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
@ -215,8 +215,8 @@ description: Variables in memory after executing i-beam.kcl
|
||||
}
|
||||
},
|
||||
"height": 72.00000000000001,
|
||||
"startCapId": null,
|
||||
"endCapId": null,
|
||||
"startCapId": "[uuid]",
|
||||
"endCapId": "[uuid]",
|
||||
"units": {
|
||||
"type": "Inches"
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
After Width: | Height: | Size: 78 KiB |
@ -4,7 +4,7 @@ use anyhow::Result;
|
||||
use indexmap::IndexMap;
|
||||
use kcl_lib::{
|
||||
exec::{ArtifactCommand, DefaultPlanes, IdGenerator},
|
||||
EngineStats, ExecutionKind, KclError,
|
||||
EngineStats, KclError,
|
||||
};
|
||||
use kittycad_modeling_cmds::{
|
||||
self as kcmc,
|
||||
@ -23,7 +23,6 @@ pub struct EngineConnection {
|
||||
batch: Arc<RwLock<Vec<(WebSocketRequest, kcl_lib::SourceRange)>>>,
|
||||
batch_end: Arc<RwLock<IndexMap<uuid::Uuid, (WebSocketRequest, kcl_lib::SourceRange)>>>,
|
||||
core_test: Arc<RwLock<String>>,
|
||||
execution_kind: Arc<RwLock<ExecutionKind>>,
|
||||
/// The default planes for the scene.
|
||||
default_planes: Arc<RwLock<Option<DefaultPlanes>>>,
|
||||
stats: EngineStats,
|
||||
@ -37,7 +36,6 @@ impl EngineConnection {
|
||||
batch: Arc::new(RwLock::new(Vec::new())),
|
||||
batch_end: Arc::new(RwLock::new(IndexMap::new())),
|
||||
core_test: result,
|
||||
execution_kind: Default::default(),
|
||||
default_planes: Default::default(),
|
||||
stats: Default::default(),
|
||||
})
|
||||
@ -379,18 +377,6 @@ impl kcl_lib::EngineManager for EngineConnection {
|
||||
Arc::new(RwLock::new(Vec::new()))
|
||||
}
|
||||
|
||||
async fn execution_kind(&self) -> ExecutionKind {
|
||||
let guard = self.execution_kind.read().await;
|
||||
*guard
|
||||
}
|
||||
|
||||
async fn replace_execution_kind(&self, execution_kind: ExecutionKind) -> ExecutionKind {
|
||||
let mut guard = self.execution_kind.write().await;
|
||||
let original = *guard;
|
||||
*guard = execution_kind;
|
||||
original
|
||||
}
|
||||
|
||||
fn get_default_planes(&self) -> Arc<RwLock<Option<DefaultPlanes>>> {
|
||||
self.default_planes.clone()
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ kcl-lib = { path = "../kcl-lib" }
|
||||
kittycad = { workspace = true }
|
||||
kittycad-modeling-cmds = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
tokio = { workspace = true, features = ["sync"] }
|
||||
tokio = { workspace = true, features = ["sync", "rt"] }
|
||||
toml = "0.8.19"
|
||||
tower-lsp = { workspace = true, features = ["runtime-agnostic"] }
|
||||
uuid = { workspace = true, features = ["v4", "js", "serde"] }
|
||||
|
@ -77,7 +77,8 @@ impl Context {
|
||||
let program: Program = serde_json::from_str(program_ast_json).map_err(|e| e.to_string())?;
|
||||
|
||||
let ctx = self.create_executor_ctx(settings, path, false)?;
|
||||
match ctx.run_with_caching(program).await {
|
||||
let mut exec_state = kcl_lib::ExecState::new(&ctx);
|
||||
match ctx.run(&program, &mut exec_state).await {
|
||||
// The serde-wasm-bindgen does not work here because of weird HashMap issues.
|
||||
// DO NOT USE serde_wasm_bindgen::to_value it will break the frontend.
|
||||
Ok(outcome) => JsValue::from_serde(&outcome).map_err(|e| e.to_string()),
|
||||
|
@ -1965,6 +1965,7 @@ export class EngineCommandManager extends EventTarget {
|
||||
range,
|
||||
idToRangeMap,
|
||||
})
|
||||
console.log("responose to wasm", resp)
|
||||
return BSON.serialize(resp[0])
|
||||
}
|
||||
/**
|
||||
|
@ -1,6 +1,6 @@
|
||||
[
|
||||
"80-20-rail",
|
||||
"a-parametric-bearing-pillow-block",
|
||||
"parametric-bearing-pillow-block",
|
||||
"ball-bearing",
|
||||
"bracket",
|
||||
"brake-caliper",
|
||||
|
@ -39,6 +39,9 @@ import {
|
||||
enableMenu,
|
||||
} from '@src/menu'
|
||||
|
||||
// If we're on Windows, pull the local system TLS CAs in
|
||||
require('win-ca')
|
||||
|
||||
let mainWindow: BrowserWindow | null = null
|
||||
|
||||
// Preemptive code, GC may delete a menu while a user is using it as seen in VSCode
|
||||
|
@ -233,7 +233,7 @@ const SignIn = () => {
|
||||
<div className="flex gap-4 flex-wrap items-center">
|
||||
<ActionButton
|
||||
Element="externalLink"
|
||||
to="https://zoo.dev/docs/kcl-samples/a-parametric-bearing-pillow-block"
|
||||
to="https://zoo.dev/docs/kcl-samples/parametric-bearing-pillow-block"
|
||||
iconStart={{
|
||||
icon: 'settings',
|
||||
bgClassName: '!bg-transparent',
|
||||
|
44
yarn.lock
44
yarn.lock
@ -6006,6 +6006,11 @@ is-date-object@^1.0.5, is-date-object@^1.1.0:
|
||||
call-bound "^1.0.2"
|
||||
has-tostringtag "^1.0.2"
|
||||
|
||||
is-electron@^2.2.0:
|
||||
version "2.2.2"
|
||||
resolved "https://registry.yarnpkg.com/is-electron/-/is-electron-2.2.2.tgz#3778902a2044d76de98036f5dc58089ac4d80bb9"
|
||||
integrity sha512-FO/Rhvz5tuw4MCWkpMzHFKWD2LsfHzIb7i6MdPYZ/KW7AlxawyLkqdy+jPZP1WubqEADE3O4FUENlJHDfQASRg==
|
||||
|
||||
is-extglob@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
|
||||
@ -6681,6 +6686,13 @@ magic-string@^0.30.5:
|
||||
dependencies:
|
||||
"@jridgewell/sourcemap-codec" "^1.5.0"
|
||||
|
||||
make-dir@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c"
|
||||
integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==
|
||||
dependencies:
|
||||
pify "^3.0.0"
|
||||
|
||||
make-error@^1.1.1:
|
||||
version "1.3.6"
|
||||
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
|
||||
@ -7027,6 +7039,11 @@ node-fetch@^3.3.2:
|
||||
fetch-blob "^3.1.4"
|
||||
formdata-polyfill "^4.0.10"
|
||||
|
||||
node-forge@^1.2.1:
|
||||
version "1.3.1"
|
||||
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.1.tgz#be8da2af243b2417d5f646a770663a92b7e9ded3"
|
||||
integrity sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==
|
||||
|
||||
node-releases@^2.0.19:
|
||||
version "2.0.19"
|
||||
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314"
|
||||
@ -7462,6 +7479,11 @@ pify@^2.0.0, pify@^2.3.0:
|
||||
resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
|
||||
integrity sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==
|
||||
|
||||
pify@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
|
||||
integrity sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==
|
||||
|
||||
pirates@^4.0.1:
|
||||
version "4.0.6"
|
||||
resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9"
|
||||
@ -8574,6 +8596,13 @@ spdx-license-ids@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.18.tgz#22aa922dcf2f2885a6494a261f2d8b75345d0326"
|
||||
integrity sha512-xxRs31BqRYHwiMzudOrpSiHtZ8i/GeionCBDSilhYRj+9gIcI8wCZTlXZKu9vZIVqViP3dcp9qE5G6AlIaD+TQ==
|
||||
|
||||
split@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9"
|
||||
integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==
|
||||
dependencies:
|
||||
through "2"
|
||||
|
||||
sprintf-js@^1.1.2, sprintf-js@^1.1.3:
|
||||
version "1.1.3"
|
||||
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.1.3.tgz#4914b903a2f8b685d17fdf78a70e917e872e444a"
|
||||
@ -8922,6 +8951,11 @@ three@^0.174.0:
|
||||
resolved "https://registry.yarnpkg.com/three/-/three-0.174.0.tgz#53f46d6fd27515231b2af321f798f1e0ecf3f905"
|
||||
integrity sha512-p+WG3W6Ov74alh3geCMkGK9NWuT62ee21cV3jEnun201zodVF4tCE5aZa2U122/mkLRmhJJUQmLLW1BH00uQJQ==
|
||||
|
||||
through@2:
|
||||
version "2.3.8"
|
||||
resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
|
||||
integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==
|
||||
|
||||
thunky@^1.0.2:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d"
|
||||
@ -9679,6 +9713,16 @@ why-is-node-running@^2.2.2:
|
||||
siginfo "^2.0.0"
|
||||
stackback "0.0.2"
|
||||
|
||||
win-ca@^3.5.1:
|
||||
version "3.5.1"
|
||||
resolved "https://registry.yarnpkg.com/win-ca/-/win-ca-3.5.1.tgz#2ef37ac24b0a1daa2714b4c5ef258c5242429e00"
|
||||
integrity sha512-RNy9gpBS6cxWHjfbqwBA7odaHyT+YQNhtdpJZwYCFoxB/Dq22oeOZ9YCXMwjhLytKpo7JJMnKdJ/ve7N12zzfQ==
|
||||
dependencies:
|
||||
is-electron "^2.2.0"
|
||||
make-dir "^1.3.0"
|
||||
node-forge "^1.2.1"
|
||||
split "^1.0.1"
|
||||
|
||||
word-wrap@^1.2.5:
|
||||
version "1.2.5"
|
||||
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34"
|
||||
|
Reference in New Issue
Block a user