big refactor of var values for astMods
This commit is contained in:
@ -40,7 +40,6 @@ import { InstanceProps, create } from 'react-modal-promise'
|
||||
import { executeAst } from 'lang/langHelpers'
|
||||
import {
|
||||
deleteSegmentFromPipeExpression,
|
||||
makeRemoveSingleConstraintInput,
|
||||
removeSingleConstraintInfo,
|
||||
} from 'lang/modifyAst'
|
||||
import { ActionButton } from 'components/ActionButton'
|
||||
@ -515,6 +514,11 @@ const ConstraintSymbol = ({
|
||||
displayName: 'Intersection Offset',
|
||||
iconName: 'intersection-offset',
|
||||
},
|
||||
radius: {
|
||||
varName: 'radius',
|
||||
displayName: 'Radius',
|
||||
iconName: 'dimension',
|
||||
},
|
||||
|
||||
// implicit constraints
|
||||
vertical: {
|
||||
@ -605,13 +609,10 @@ const ConstraintSymbol = ({
|
||||
if (trap(_node1)) return Promise.reject(_node1)
|
||||
const shallowPath = _node1.shallowPath
|
||||
|
||||
const input = makeRemoveSingleConstraintInput(
|
||||
argPosition,
|
||||
shallowPath
|
||||
)
|
||||
if (!input || !context.sketchDetails) return
|
||||
if (!context.sketchDetails || !argPosition) return
|
||||
const transform = removeSingleConstraintInfo(
|
||||
input,
|
||||
shallowPath,
|
||||
argPosition,
|
||||
kclManager.ast,
|
||||
kclManager.programMemory
|
||||
)
|
||||
|
||||
@ -89,6 +89,7 @@ import {
|
||||
createArrayExpression,
|
||||
createCallExpressionStdLib,
|
||||
createLiteral,
|
||||
createObjectExpression,
|
||||
createPipeExpression,
|
||||
createPipeSubstitution,
|
||||
findUniqueName,
|
||||
@ -108,6 +109,7 @@ import { getThemeColorForThreeJs } from 'lib/theme'
|
||||
import { err, trap } from 'lib/trap'
|
||||
import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer'
|
||||
import { Point3d } from 'wasm-lib/kcl/bindings/Point3d'
|
||||
import { c } from 'vite/dist/node/types.d-aGj9QkWt'
|
||||
|
||||
type DraftSegment = 'line' | 'tangentialArcTo'
|
||||
|
||||
@ -665,8 +667,11 @@ export class SceneEntities {
|
||||
const mod = addNewSketchLn({
|
||||
node: _ast,
|
||||
programMemory: kclManager.programMemory,
|
||||
to: [lastSeg.to[0], lastSeg.to[1]],
|
||||
from: [lastSeg.to[0], lastSeg.to[1]],
|
||||
input: {
|
||||
type: 'straight-segment',
|
||||
to: [lastSeg.to[0], lastSeg.to[1]],
|
||||
from: [lastSeg.to[0], lastSeg.to[1]],
|
||||
},
|
||||
fnName: segmentName,
|
||||
pathToNode: sketchPathToNode,
|
||||
})
|
||||
@ -736,8 +741,11 @@ export class SceneEntities {
|
||||
const tmp = addNewSketchLn({
|
||||
node: kclManager.ast,
|
||||
programMemory: kclManager.programMemory,
|
||||
to: [intersection2d.x, intersection2d.y],
|
||||
from: [lastSegment.to[0], lastSegment.to[1]],
|
||||
input: {
|
||||
type: 'straight-segment',
|
||||
to: [intersection2d.x, intersection2d.y],
|
||||
from: [lastSegment.to[0], lastSegment.to[1]],
|
||||
},
|
||||
fnName:
|
||||
lastSegment.type === 'TangentialArcTo'
|
||||
? 'tangentialArcTo'
|
||||
@ -962,11 +970,13 @@ export class SceneEntities {
|
||||
startSketchOn[0].init = createPipeExpression([
|
||||
startSketchOnInit,
|
||||
createCallExpressionStdLib('circle', [
|
||||
createArrayExpression([
|
||||
createLiteral(roundOff(circleCenter[0])),
|
||||
createLiteral(roundOff(circleCenter[1])),
|
||||
]),
|
||||
createLiteral(1),
|
||||
createObjectExpression({
|
||||
center: createArrayExpression([
|
||||
createLiteral(roundOff(circleCenter[0])),
|
||||
createLiteral(roundOff(circleCenter[1])),
|
||||
]),
|
||||
radius: createLiteral(1),
|
||||
}),
|
||||
createPipeSubstitution(),
|
||||
]),
|
||||
])
|
||||
@ -1147,8 +1157,11 @@ export class SceneEntities {
|
||||
const mod = addNewSketchLn({
|
||||
node: kclManager.ast,
|
||||
programMemory: kclManager.programMemory,
|
||||
to: [intersectionPoint.twoD.x, intersectionPoint.twoD.y],
|
||||
from: [prevSegment.from[0], prevSegment.from[1]],
|
||||
input: {
|
||||
type: 'straight-segment',
|
||||
to: [intersectionPoint.twoD.x, intersectionPoint.twoD.y],
|
||||
from: [prevSegment.from[0], prevSegment.from[1]],
|
||||
},
|
||||
// TODO assuming it's always a straight segments being added
|
||||
// as this is easiest, and we'll need to add "tabbing" behavior
|
||||
// to support other segment types
|
||||
@ -1293,41 +1306,55 @@ export class SceneEntities {
|
||||
modded = updateStartProfileAtArgs({
|
||||
node: modifiedAst,
|
||||
pathToNode,
|
||||
to: dragTo,
|
||||
from,
|
||||
input: {
|
||||
type: 'straight-segment',
|
||||
to: dragTo,
|
||||
from,
|
||||
},
|
||||
previousProgramMemory: kclManager.programMemory,
|
||||
})
|
||||
} else if (group.name === CIRCLE_SEGMENT && subGroup?.name === ARROWHEAD) {
|
||||
// is dragging the radius handle
|
||||
modded = changeCircleArguments(
|
||||
|
||||
modded = changeSketchArguments(
|
||||
modifiedAst,
|
||||
kclManager.programMemory,
|
||||
getNodePathFromSourceRange(modifiedAst, [node.start, node.end]),
|
||||
group.userData.center,
|
||||
Math.sqrt(
|
||||
(group.userData.center[0] - dragTo[0]) ** 2 +
|
||||
(group.userData.center[0] - dragTo[0]) ** 2
|
||||
)
|
||||
[node.start, node.end],
|
||||
{
|
||||
type: 'arc-segment',
|
||||
from,
|
||||
center: group.userData.center,
|
||||
radius: Math.sqrt(
|
||||
(group.userData.center[0] - dragTo[0]) ** 2 +
|
||||
(group.userData.center[0] - dragTo[0]) ** 2
|
||||
),
|
||||
}
|
||||
)
|
||||
} else if (
|
||||
group.name === CIRCLE_SEGMENT &&
|
||||
subGroup?.name === CIRCLE_CENTER_HANDLE
|
||||
) {
|
||||
// is dragging the center handle
|
||||
modded = changeCircleArguments(
|
||||
modded = changeSketchArguments(
|
||||
modifiedAst,
|
||||
kclManager.programMemory,
|
||||
getNodePathFromSourceRange(modifiedAst, [node.start, node.end]),
|
||||
dragTo,
|
||||
group.userData.radius
|
||||
[node.start, node.end],
|
||||
{
|
||||
type: 'arc-segment',
|
||||
from,
|
||||
center: dragTo,
|
||||
radius: group.userData.radius,
|
||||
}
|
||||
)
|
||||
} else {
|
||||
modded = changeSketchArguments(
|
||||
modifiedAst,
|
||||
kclManager.programMemory,
|
||||
[node.start, node.end],
|
||||
dragTo,
|
||||
from
|
||||
{
|
||||
type: 'straight-segment',
|
||||
from,
|
||||
to: dragTo,
|
||||
}
|
||||
)
|
||||
}
|
||||
if (trap(modded)) return
|
||||
@ -1683,7 +1710,7 @@ export class SceneEntities {
|
||||
arrowGroup,
|
||||
group,
|
||||
isHandlesVisible,
|
||||
from,
|
||||
from: to,
|
||||
to: [center[0], center[1]],
|
||||
angle,
|
||||
})
|
||||
|
||||
@ -24,11 +24,9 @@ export type ToolTip =
|
||||
| 'yLineTo'
|
||||
| 'angledLineThatIntersects'
|
||||
| 'tangentialArcTo'
|
||||
| 'circle'
|
||||
|
||||
export const toolTips = [
|
||||
'sketch_line',
|
||||
'move',
|
||||
// original tooltips
|
||||
export const toolTips: Array<ToolTip> = [
|
||||
'line',
|
||||
'lineTo',
|
||||
'angledLine',
|
||||
@ -42,7 +40,7 @@ export const toolTips = [
|
||||
'yLineTo',
|
||||
'angledLineThatIntersects',
|
||||
'tangentialArcTo',
|
||||
] as any as ToolTip[]
|
||||
]
|
||||
|
||||
export async function executeAst({
|
||||
ast,
|
||||
|
||||
@ -20,6 +20,7 @@ import {
|
||||
import { enginelessExecutor } from '../lib/testHelpers'
|
||||
import { findUsesOfTagInPipe, getNodePathFromSourceRange } from './queryAst'
|
||||
import { err } from 'lib/trap'
|
||||
import { SimplifiedVarValue, VarValueKeys } from './std/stdTypes'
|
||||
|
||||
beforeAll(async () => {
|
||||
await initPromise
|
||||
@ -638,11 +639,21 @@ describe('Testing removeSingleConstraintInfo', () => {
|
||||
code.indexOf(lineOfInterest) + lineOfInterest.length,
|
||||
]
|
||||
const pathToNode = getNodePathFromSourceRange(ast, range)
|
||||
let argPosition: SimplifiedVarValue
|
||||
if (key === 'arrayIndex' && typeof value === 'number') {
|
||||
argPosition = { type: 'arrayItem', argIndex: 0, index: value ? 0 : 1 }
|
||||
} else if (key === 'objectProperty' && typeof value === 'string') {
|
||||
argPosition = {
|
||||
type: 'objectProperty',
|
||||
key: value as VarValueKeys,
|
||||
argIndex: 0,
|
||||
}
|
||||
} else {
|
||||
throw new Error('argPosition is undefined')
|
||||
}
|
||||
const mod = removeSingleConstraintInfo(
|
||||
{
|
||||
pathToCallExp: pathToNode,
|
||||
[key]: value,
|
||||
},
|
||||
pathToNode,
|
||||
argPosition,
|
||||
ast,
|
||||
programMemory
|
||||
)
|
||||
@ -675,12 +686,22 @@ describe('Testing removeSingleConstraintInfo', () => {
|
||||
code.indexOf(lineOfInterest) + 1,
|
||||
code.indexOf(lineOfInterest) + lineOfInterest.length,
|
||||
]
|
||||
let argPosition: SimplifiedVarValue
|
||||
if (key === 'arrayIndex' && typeof value === 'number') {
|
||||
argPosition = { type: 'arrayItem', argIndex: 0, index: value ? 0 : 1 }
|
||||
} else if (key === 'objectProperty' && typeof value === 'string') {
|
||||
argPosition = {
|
||||
type: 'objectProperty',
|
||||
key: value as VarValueKeys,
|
||||
argIndex: 0,
|
||||
}
|
||||
} else {
|
||||
throw new Error('argPosition is undefined')
|
||||
}
|
||||
const pathToNode = getNodePathFromSourceRange(ast, range)
|
||||
const mod = removeSingleConstraintInfo(
|
||||
{
|
||||
pathToCallExp: pathToNode,
|
||||
[key]: value,
|
||||
},
|
||||
pathToNode,
|
||||
argPosition,
|
||||
ast,
|
||||
programMemory
|
||||
)
|
||||
|
||||
@ -38,7 +38,7 @@ import {
|
||||
import { DefaultPlaneStr } from 'clientSideScene/sceneEntities'
|
||||
import { isOverlap, roundOff } from 'lib/utils'
|
||||
import { KCL_DEFAULT_CONSTANT_PREFIXES } from 'lib/constants'
|
||||
import { ConstrainInfo } from './std/stdTypes'
|
||||
import { SimplifiedVarValue } from './std/stdTypes'
|
||||
import { TagDeclarator } from 'wasm-lib/kcl/bindings/TagDeclarator'
|
||||
import { Models } from '@kittycad/lib'
|
||||
|
||||
@ -799,15 +799,10 @@ export function deleteSegmentFromPipeExpression(
|
||||
)
|
||||
if (!constraintInfo) return
|
||||
|
||||
const input = makeRemoveSingleConstraintInput(
|
||||
constraintInfo.argPosition,
|
||||
callExp.shallowPath
|
||||
)
|
||||
if (!input) return
|
||||
if (!constraintInfo.argPosition) return
|
||||
const transform = removeSingleConstraintInfo(
|
||||
{
|
||||
...input,
|
||||
},
|
||||
callExp.shallowPath,
|
||||
constraintInfo.argPosition,
|
||||
_modifiedAst,
|
||||
programMemory
|
||||
)
|
||||
@ -834,37 +829,9 @@ export function deleteSegmentFromPipeExpression(
|
||||
return _modifiedAst
|
||||
}
|
||||
|
||||
export function makeRemoveSingleConstraintInput(
|
||||
argPosition: ConstrainInfo['argPosition'],
|
||||
pathToNode: PathToNode
|
||||
): Parameters<typeof removeSingleConstraintInfo>[0] | false {
|
||||
return argPosition?.type === 'singleValue'
|
||||
? {
|
||||
pathToCallExp: pathToNode,
|
||||
}
|
||||
: argPosition?.type === 'arrayItem'
|
||||
? {
|
||||
pathToCallExp: pathToNode,
|
||||
arrayIndex: argPosition.index,
|
||||
}
|
||||
: argPosition?.type === 'objectProperty'
|
||||
? {
|
||||
pathToCallExp: pathToNode,
|
||||
objectProperty: argPosition.key,
|
||||
}
|
||||
: false
|
||||
}
|
||||
|
||||
export function removeSingleConstraintInfo(
|
||||
{
|
||||
pathToCallExp,
|
||||
arrayIndex,
|
||||
objectProperty,
|
||||
}: {
|
||||
pathToCallExp: PathToNode
|
||||
arrayIndex?: number
|
||||
objectProperty?: string
|
||||
},
|
||||
pathToCallExp: PathToNode,
|
||||
varValue: SimplifiedVarValue,
|
||||
ast: Program,
|
||||
programMemory: ProgramMemory
|
||||
):
|
||||
@ -875,8 +842,7 @@ export function removeSingleConstraintInfo(
|
||||
| false {
|
||||
const transform = removeSingleConstraint({
|
||||
pathToCallExp,
|
||||
arrayIndex,
|
||||
objectProperty,
|
||||
inputDetails: varValue,
|
||||
ast,
|
||||
})
|
||||
if (!transform) return false
|
||||
|
||||
@ -16,6 +16,7 @@ import {
|
||||
VariableDeclaration,
|
||||
VariableDeclarator,
|
||||
sketchGroupFromKclValue,
|
||||
ObjectExpression,
|
||||
} from './wasm'
|
||||
import { createIdentifier, splitPathAtLastIndex } from './modifyAst'
|
||||
import { getSketchSegmentFromSourceRange } from './std/sketchConstraints'
|
||||
@ -934,3 +935,12 @@ export function hasExtrudableGeometry(ast: Program) {
|
||||
})
|
||||
return Object.keys(theMap).length > 0
|
||||
}
|
||||
|
||||
export function getObjExpProperty(
|
||||
node: ObjectExpression,
|
||||
propName: string
|
||||
): { exp: Expr; index: number } | null {
|
||||
const index = node.properties.findIndex(({ key }) => key.name === propName)
|
||||
if (index === -1) return null
|
||||
return { exp: node.properties[index].value, index }
|
||||
}
|
||||
|
||||
@ -123,8 +123,11 @@ describe('testing changeSketchArguments', () => {
|
||||
ast,
|
||||
programMemory,
|
||||
[sourceStart, sourceStart + lineToChange.length],
|
||||
[2, 3],
|
||||
[0, 0]
|
||||
{
|
||||
type: 'straight-segment',
|
||||
from: [0, 0],
|
||||
to: [2, 3],
|
||||
}
|
||||
)
|
||||
if (err(changeSketchArgsRetVal)) return changeSketchArgsRetVal
|
||||
expect(recast(changeSketchArgsRetVal.modifiedAst)).toBe(expectedCode)
|
||||
@ -150,8 +153,11 @@ const mySketch001 = startSketchOn('XY')
|
||||
const newSketchLnRetVal = addNewSketchLn({
|
||||
node: ast,
|
||||
programMemory,
|
||||
to: [2, 3],
|
||||
from: [0, 0],
|
||||
input: {
|
||||
type: 'straight-segment',
|
||||
from: [0, 0],
|
||||
to: [2, 3],
|
||||
},
|
||||
fnName: 'lineTo',
|
||||
pathToNode: [
|
||||
['body', ''],
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -43,6 +43,16 @@ export function getSketchSegmentFromSourceRange(
|
||||
index: number
|
||||
}
|
||||
| Error {
|
||||
const lineIndex = sketchGroup.value.findIndex(
|
||||
({ __geoMeta: { sourceRange } }: Path) =>
|
||||
sourceRange[0] <= rangeStart && sourceRange[1] >= rangeEnd
|
||||
)
|
||||
const line = sketchGroup.value[lineIndex]
|
||||
if (line)
|
||||
return {
|
||||
segment: line,
|
||||
index: lineIndex,
|
||||
}
|
||||
const startSourceRange = sketchGroup.start?.__geoMeta.sourceRange
|
||||
if (
|
||||
startSourceRange &&
|
||||
@ -51,17 +61,7 @@ export function getSketchSegmentFromSourceRange(
|
||||
sketchGroup.start
|
||||
)
|
||||
return { segment: { ...sketchGroup.start, type: 'Base' }, index: -1 }
|
||||
|
||||
const lineIndex = sketchGroup.value.findIndex(
|
||||
({ __geoMeta: { sourceRange } }: Path) =>
|
||||
sourceRange[0] <= rangeStart && sourceRange[1] >= rangeEnd
|
||||
)
|
||||
const line = sketchGroup.value[lineIndex]
|
||||
if (!line) return new Error('could not find matching line')
|
||||
return {
|
||||
segment: line,
|
||||
index: lineIndex,
|
||||
}
|
||||
return new Error('could not find matching segment')
|
||||
}
|
||||
|
||||
export function isSketchVariablesLinked(
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -37,9 +37,36 @@ export interface AddTagInfo {
|
||||
pathToNode: PathToNode
|
||||
}
|
||||
|
||||
interface addCall extends ModifyAstBase {
|
||||
to: [number, number]
|
||||
/** Inputs for all straight segments, to and from are absolute values, as this gives a
|
||||
* consistent base that can be converted to all of the line, angledLine, etc segment types
|
||||
* One notable exception to "straight segment" is that tangentialArcTo is included in this
|
||||
* Input type since it too only takes x-y values and is able to get extra info it needs
|
||||
* to be tangential from the previous segment */
|
||||
interface StraightSegmentInput {
|
||||
type: 'straight-segment'
|
||||
from: [number, number]
|
||||
to: [number, number]
|
||||
}
|
||||
|
||||
/** Inputs for arcs, excluding tangentialArcTo for reasons explain in
|
||||
* the @straightSegmentInput comment */
|
||||
interface ArcSegmentInput {
|
||||
type: 'arc-segment'
|
||||
from: [number, number]
|
||||
center: [number, number]
|
||||
radius: number
|
||||
}
|
||||
|
||||
/**
|
||||
* SegmentInputs is a union type that can be either a StraightSegmentInput or an ArcSegmentInput.
|
||||
*
|
||||
* - StraightSegmentInput: Represents a straight segment with a starting point (from) and an ending point (to).
|
||||
* - ArcSegmentInput: Represents an arc segment with a starting point (from), a center point, and a radius.
|
||||
*/
|
||||
export type SegmentInputs = StraightSegmentInput | ArcSegmentInput
|
||||
|
||||
interface addCall extends ModifyAstBase {
|
||||
input: SegmentInputs
|
||||
referencedSegment?: Path
|
||||
replaceExisting?: boolean
|
||||
createCallback?: TransformCallback // TODO: #29 probably should not be optional
|
||||
@ -48,35 +75,54 @@ interface addCall extends ModifyAstBase {
|
||||
}
|
||||
|
||||
interface updateArgs extends ModifyAstBase {
|
||||
from: [number, number]
|
||||
to: [number, number]
|
||||
input: SegmentInputs
|
||||
}
|
||||
|
||||
export type VarValueKeys = 'angle' | 'offset' | 'length' | 'to' | 'intersectTag'
|
||||
export type VarValueKeys =
|
||||
| 'angle'
|
||||
| 'offset'
|
||||
| 'length'
|
||||
| 'to'
|
||||
| 'intersectTag'
|
||||
| 'radius'
|
||||
| 'center'
|
||||
export interface SingleValueInput<T> {
|
||||
type: 'singleValue'
|
||||
argType: LineInputsType
|
||||
argType: LineInputsType | 'radius'
|
||||
value: T
|
||||
argIndex: number
|
||||
}
|
||||
export interface ArrayItemInput<T> {
|
||||
type: 'arrayItem'
|
||||
index: 0 | 1
|
||||
argType: LineInputsType
|
||||
argType: LineInputsType | 'radius'
|
||||
value: T
|
||||
argIndex: number
|
||||
}
|
||||
export interface ObjectPropertyInput<T> {
|
||||
type: 'objectProperty'
|
||||
key: VarValueKeys
|
||||
argType: LineInputsType
|
||||
argType: LineInputsType | 'radius'
|
||||
value: T
|
||||
argIndex: number
|
||||
}
|
||||
|
||||
export interface ArrayOrObjItemInput<T> {
|
||||
type: 'arrayOrObjItem'
|
||||
key: VarValueKeys
|
||||
index: 0 | 1
|
||||
argType: LineInputsType
|
||||
argType: LineInputsType | 'radius'
|
||||
value: T
|
||||
argIndex: number
|
||||
}
|
||||
|
||||
export interface ObjectPropertyArrayInput<T> {
|
||||
type: 'objectPropertyArray'
|
||||
key: VarValueKeys
|
||||
argType: LineInputsType | 'radius'
|
||||
index: 0 | 1
|
||||
value: T
|
||||
argIndex: number
|
||||
}
|
||||
|
||||
export type _VarValue<T> =
|
||||
@ -84,6 +130,7 @@ export type _VarValue<T> =
|
||||
| ArrayItemInput<T>
|
||||
| ObjectPropertyInput<T>
|
||||
| ArrayOrObjItemInput<T>
|
||||
| ObjectPropertyArrayInput<T>
|
||||
|
||||
export type VarValue = _VarValue<Expr>
|
||||
export type RawValue = _VarValue<Literal>
|
||||
@ -91,16 +138,25 @@ export type RawValue = _VarValue<Literal>
|
||||
export type VarValues = Array<VarValue>
|
||||
export type RawValues = Array<RawValue>
|
||||
|
||||
type SimplifiedVarValue =
|
||||
export type SimplifiedVarValue =
|
||||
| {
|
||||
type: 'singleValue'
|
||||
argIndex: number
|
||||
}
|
||||
| { type: 'arrayItem'; index: 0 | 1; argIndex: number }
|
||||
| { type: 'objectProperty'; key: VarValueKeys; argIndex: number }
|
||||
| {
|
||||
type: 'arrayInObject'
|
||||
key: VarValueKeys
|
||||
index: 0 | 1
|
||||
}
|
||||
| { type: 'arrayItem'; index: 0 | 1 }
|
||||
| { type: 'objectProperty'; key: VarValueKeys }
|
||||
|
||||
export type TransformCallback = (
|
||||
args: [Expr, Expr],
|
||||
literalValues: RawValues,
|
||||
// args: Array<Expr>,
|
||||
inputs: {
|
||||
varExpression: Expr
|
||||
varDetails: VarValue
|
||||
}[],
|
||||
referencedSegment?: Path
|
||||
) => {
|
||||
callExp: Expr
|
||||
@ -109,7 +165,12 @@ export type TransformCallback = (
|
||||
|
||||
export interface ConstrainInfo {
|
||||
stdLibFnName: ToolTip
|
||||
type: LineInputsType | 'vertical' | 'horizontal' | 'tangentialWithPrevious'
|
||||
type:
|
||||
| LineInputsType
|
||||
| 'vertical'
|
||||
| 'horizontal'
|
||||
| 'tangentialWithPrevious'
|
||||
| 'radius'
|
||||
isConstrained: boolean
|
||||
sourceRange: SourceRange
|
||||
pathToNode: PathToNode
|
||||
|
||||
Reference in New Issue
Block a user