diff --git a/e2e/playwright/snapshot-tests.spec.ts-snapshots/code-color-goober-code-color-goober-1-Google-Chrome-linux.png b/e2e/playwright/snapshot-tests.spec.ts-snapshots/code-color-goober-code-color-goober-1-Google-Chrome-linux.png index 04e56c137..5e3af722a 100644 Binary files a/e2e/playwright/snapshot-tests.spec.ts-snapshots/code-color-goober-code-color-goober-1-Google-Chrome-linux.png and b/e2e/playwright/snapshot-tests.spec.ts-snapshots/code-color-goober-code-color-goober-1-Google-Chrome-linux.png differ diff --git a/src/clientSideScene/sceneEntities.ts b/src/clientSideScene/sceneEntities.ts index 66cd0b594..02de3e2aa 100644 --- a/src/clientSideScene/sceneEntities.ts +++ b/src/clientSideScene/sceneEntities.ts @@ -69,7 +69,8 @@ import { codeManager, editorManager, } from 'lib/singletons' -import { getNodeFromPath, getNodePathFromSourceRange } from 'lang/queryAst' +import { getNodeFromPath } from 'lang/queryAst' +import { getNodePathFromSourceRange } from 'lang/queryAstNodePathUtils' import { executeAst, ToolTip } from 'lang/langHelpers' import { createProfileStartHandle, diff --git a/src/components/AstExplorer.tsx b/src/components/AstExplorer.tsx index 8878c2203..ee0a7e5e6 100644 --- a/src/components/AstExplorer.tsx +++ b/src/components/AstExplorer.tsx @@ -1,6 +1,7 @@ import { useModelingContext } from 'hooks/useModelingContext' import { editorManager, engineCommandManager, kclManager } from 'lib/singletons' -import { getNodeFromPath, getNodePathFromSourceRange } from 'lang/queryAst' +import { getNodeFromPath } from 'lang/queryAst' +import { getNodePathFromSourceRange } from 'lang/queryAstNodePathUtils' import { useEffect, useRef, useState } from 'react' import { trap } from 'lib/trap' import { codeToIdSelections } from 'lib/selections' diff --git a/src/components/ModelingMachineProvider.tsx b/src/components/ModelingMachineProvider.tsx index 111aa2aaf..dbcfd8b71 100644 --- a/src/components/ModelingMachineProvider.tsx +++ b/src/components/ModelingMachineProvider.tsx @@ -68,11 +68,8 @@ import { startSketchOnDefault, } from 'lang/modifyAst' import { PathToNode, Program, parse, recast, resultIsOk } from 'lang/wasm' -import { - artifactIsPlaneWithPaths, - getNodePathFromSourceRange, - isSingleCursorInPipe, -} from 'lang/queryAst' +import { artifactIsPlaneWithPaths, isSingleCursorInPipe } from 'lang/queryAst' +import { getNodePathFromSourceRange } from 'lang/queryAstNodePathUtils' import { exportFromEngine } from 'lib/exportFromEngine' import { Models } from '@kittycad/lib/dist/types/src' import toast from 'react-hot-toast' diff --git a/src/components/Toolbar/EqualAngle.tsx b/src/components/Toolbar/EqualAngle.tsx index d3df54bed..98862ef61 100644 --- a/src/components/Toolbar/EqualAngle.tsx +++ b/src/components/Toolbar/EqualAngle.tsx @@ -1,10 +1,8 @@ import { toolTips } from 'lang/langHelpers' import { Selections } from 'lib/selections' import { Program, Expr, VariableDeclarator } from '../../lang/wasm' -import { - getNodePathFromSourceRange, - getNodeFromPath, -} from '../../lang/queryAst' +import { getNodeFromPath } from '../../lang/queryAst' +import { getNodePathFromSourceRange } from 'lang/queryAstNodePathUtils' import { isSketchVariablesLinked } from '../../lang/std/sketchConstraints' import { transformSecondarySketchLinesTagFirst, diff --git a/src/hooks/useEngineConnectionSubscriptions.ts b/src/hooks/useEngineConnectionSubscriptions.ts index ec2a34761..a476b0ff2 100644 --- a/src/hooks/useEngineConnectionSubscriptions.ts +++ b/src/hooks/useEngineConnectionSubscriptions.ts @@ -17,7 +17,8 @@ import { } from 'lang/std/artifactGraph' import { err, reportRejection } from 'lib/trap' import { DefaultPlaneStr, getFaceDetails } from 'clientSideScene/sceneEntities' -import { getNodeFromPath, getNodePathFromSourceRange } from 'lang/queryAst' +import { getNodeFromPath } from 'lang/queryAst' +import { getNodePathFromSourceRange } from 'lang/queryAstNodePathUtils' import { CallExpression, defaultSourceRange } from 'lang/wasm' import { EdgeCutInfo, ExtrudeFacePlane } from 'machines/modelingMachine' diff --git a/src/lang/getNodePathFromSourceRange.test.ts b/src/lang/getNodePathFromSourceRange.test.ts index e48b019ab..f5b83b2c2 100644 --- a/src/lang/getNodePathFromSourceRange.test.ts +++ b/src/lang/getNodePathFromSourceRange.test.ts @@ -1,4 +1,5 @@ -import { getNodePathFromSourceRange, getNodeFromPath } from './queryAst' +import { getNodeFromPath } from './queryAst' +import { getNodePathFromSourceRange } from 'lang/queryAstNodePathUtils' import { Identifier, assertParse, diff --git a/src/lang/modifyAst.test.ts b/src/lang/modifyAst.test.ts index 52ea0f624..c78b45c2d 100644 --- a/src/lang/modifyAst.test.ts +++ b/src/lang/modifyAst.test.ts @@ -25,7 +25,8 @@ import { deleteFromSelection, } from './modifyAst' import { enginelessExecutor } from '../lib/testHelpers' -import { findUsesOfTagInPipe, getNodePathFromSourceRange } from './queryAst' +import { findUsesOfTagInPipe } from './queryAst' +import { getNodePathFromSourceRange } from 'lang/queryAstNodePathUtils' import { err } from 'lib/trap' import { SimplifiedArgDetails } from './std/stdTypes' import { Node } from 'wasm-lib/kcl/bindings/Node' diff --git a/src/lang/modifyAst.ts b/src/lang/modifyAst.ts index d94b13329..a4d2ec076 100644 --- a/src/lang/modifyAst.ts +++ b/src/lang/modifyAst.ts @@ -26,10 +26,10 @@ import { findAllPreviousVariables, findAllPreviousVariablesPath, getNodeFromPath, - getNodePathFromSourceRange, isNodeSafeToReplace, traverse, } from './queryAst' +import { getNodePathFromSourceRange } from 'lang/queryAstNodePathUtils' import { addTagForSketchOnFace, getConstraintInfo } from './std/sketch' import { PathToNodeMap, diff --git a/src/lang/modifyAst/addEdgeTreatment.test.ts b/src/lang/modifyAst/addEdgeTreatment.test.ts index 65293f8a5..ea3ddd5c1 100644 --- a/src/lang/modifyAst/addEdgeTreatment.test.ts +++ b/src/lang/modifyAst/addEdgeTreatment.test.ts @@ -21,7 +21,8 @@ import { ChamferParameters, EdgeTreatmentParameters, } from './addEdgeTreatment' -import { getNodeFromPath, getNodePathFromSourceRange } from '../queryAst' +import { getNodeFromPath } from '../queryAst' +import { getNodePathFromSourceRange } from 'lang/queryAstNodePathUtils' import { createLiteral } from 'lang/modifyAst' import { err } from 'lib/trap' import { Selection, Selections } from 'lib/selections' diff --git a/src/lang/modifyAst/addEdgeTreatment.ts b/src/lang/modifyAst/addEdgeTreatment.ts index 53ca8bc01..0b91125ad 100644 --- a/src/lang/modifyAst/addEdgeTreatment.ts +++ b/src/lang/modifyAst/addEdgeTreatment.ts @@ -20,10 +20,10 @@ import { } from '../modifyAst' import { getNodeFromPath, - getNodePathFromSourceRange, hasSketchPipeBeenExtruded, traverse, } from '../queryAst' +import { getNodePathFromSourceRange } from 'lang/queryAstNodePathUtils' import { addTagForSketchOnFace, getTagFromCallExpression, diff --git a/src/lang/modifyAst/addRevolve.ts b/src/lang/modifyAst/addRevolve.ts index 2ac2a90c3..1b5c86801 100644 --- a/src/lang/modifyAst/addRevolve.ts +++ b/src/lang/modifyAst/addRevolve.ts @@ -19,7 +19,8 @@ import { findUniqueName, createVariableDeclaration, } from 'lang/modifyAst' -import { getNodeFromPath, getNodePathFromSourceRange } from 'lang/queryAst' +import { getNodeFromPath } from 'lang/queryAst' +import { getNodePathFromSourceRange } from 'lang/queryAstNodePathUtils' import { mutateAstWithTagForSketchSegment, getEdgeTagCall, diff --git a/src/lang/queryAst.test.ts b/src/lang/queryAst.test.ts index 0eefee96d..a771d0284 100644 --- a/src/lang/queryAst.test.ts +++ b/src/lang/queryAst.test.ts @@ -10,7 +10,6 @@ import { findAllPreviousVariables, isNodeSafeToReplace, isTypeInValue, - getNodePathFromSourceRange, hasExtrudeSketch, findUsesOfTagInPipe, hasSketchPipeBeenExtruded, @@ -19,6 +18,7 @@ import { getNodeFromPath, doesSceneHaveExtrudedSketch, } from './queryAst' +import { getNodePathFromSourceRange } from 'lang/queryAstNodePathUtils' import { enginelessExecutor } from '../lib/testHelpers' import { createArrayExpression, diff --git a/src/lang/queryAst.ts b/src/lang/queryAst.ts index 7b7e79a94..12b3f2f55 100644 --- a/src/lang/queryAst.ts +++ b/src/lang/queryAst.ts @@ -22,6 +22,7 @@ import { VariableDeclaration, VariableDeclarator, } from './wasm' +import { getNodePathFromSourceRange } from 'lang/queryAstNodePathUtils' import { createIdentifier, splitPathAtLastIndex } from './modifyAst' import { getSketchSegmentFromSourceRange } from './std/sketchConstraints' import { getAngle } from '../lib/utils' @@ -125,311 +126,6 @@ export function getNodeFromPathCurry( } } -function moreNodePathFromSourceRange( - node: Node< - | Expr - | ImportStatement - | ExpressionStatement - | VariableDeclaration - | ReturnStatement - >, - sourceRange: SourceRange, - previousPath: PathToNode = [['body', '']] -): PathToNode { - const [start, end] = sourceRange - let path: PathToNode = [...previousPath] - const _node = { ...node } - - if (start < _node.start || end > _node.end) return path - - const isInRange = _node.start <= start && _node.end >= end - - if ( - (_node.type === 'Identifier' || - _node.type === 'Literal' || - _node.type === 'TagDeclarator') && - isInRange - ) { - return path - } - - if (_node.type === 'CallExpression' && isInRange) { - const { callee, arguments: args } = _node - if ( - callee.type === 'Identifier' && - callee.start <= start && - callee.end >= end - ) { - path.push(['callee', 'CallExpression']) - return path - } - if (args.length > 0) { - for (let argIndex = 0; argIndex < args.length; argIndex++) { - const arg = args[argIndex] - if (arg.start <= start && arg.end >= end) { - path.push(['arguments', 'CallExpression']) - path.push([argIndex, 'index']) - return moreNodePathFromSourceRange(arg, sourceRange, path) - } - } - } - return path - } - - if (_node.type === 'CallExpressionKw' && isInRange) { - const { callee, arguments: args } = _node - if ( - callee.type === 'Identifier' && - callee.start <= start && - callee.end >= end - ) { - path.push(['callee', 'CallExpressionKw']) - return path - } - if (args.length > 0) { - for (let argIndex = 0; argIndex < args.length; argIndex++) { - const arg = args[argIndex].arg - if (arg.start <= start && arg.end >= end) { - path.push(['arguments', 'CallExpressionKw']) - path.push([argIndex, 'index']) - return moreNodePathFromSourceRange(arg, sourceRange, path) - } - } - } - return path - } - - if (_node.type === 'BinaryExpression' && isInRange) { - const { left, right } = _node - if (left.start <= start && left.end >= end) { - path.push(['left', 'BinaryExpression']) - return moreNodePathFromSourceRange(left, sourceRange, path) - } - if (right.start <= start && right.end >= end) { - path.push(['right', 'BinaryExpression']) - return moreNodePathFromSourceRange(right, sourceRange, path) - } - return path - } - if (_node.type === 'PipeExpression' && isInRange) { - const { body } = _node - for (let i = 0; i < body.length; i++) { - const pipe = body[i] - if (pipe.start <= start && pipe.end >= end) { - path.push(['body', 'PipeExpression']) - path.push([i, 'index']) - return moreNodePathFromSourceRange(pipe, sourceRange, path) - } - } - return path - } - if (_node.type === 'ArrayExpression' && isInRange) { - const { elements } = _node - for (let elIndex = 0; elIndex < elements.length; elIndex++) { - const element = elements[elIndex] - if (element.start <= start && element.end >= end) { - path.push(['elements', 'ArrayExpression']) - path.push([elIndex, 'index']) - return moreNodePathFromSourceRange(element, sourceRange, path) - } - } - return path - } - if (_node.type === 'ObjectExpression' && isInRange) { - const { properties } = _node - for (let propIndex = 0; propIndex < properties.length; propIndex++) { - const property = properties[propIndex] - if (property.start <= start && property.end >= end) { - path.push(['properties', 'ObjectExpression']) - path.push([propIndex, 'index']) - if (property.key.start <= start && property.key.end >= end) { - path.push(['key', 'Property']) - return moreNodePathFromSourceRange(property.key, sourceRange, path) - } - if (property.value.start <= start && property.value.end >= end) { - path.push(['value', 'Property']) - return moreNodePathFromSourceRange(property.value, sourceRange, path) - } - } - } - return path - } - if (_node.type === 'ExpressionStatement' && isInRange) { - const { expression } = _node - path.push(['expression', 'ExpressionStatement']) - return moreNodePathFromSourceRange(expression, sourceRange, path) - } - if (_node.type === 'VariableDeclaration' && isInRange) { - const declaration = _node.declaration - - if (declaration.start <= start && declaration.end >= end) { - path.push(['declaration', 'VariableDeclaration']) - const init = declaration.init - if (init.start <= start && init.end >= end) { - path.push(['init', '']) - return moreNodePathFromSourceRange(init, sourceRange, path) - } - } - } - if (_node.type === 'VariableDeclaration' && isInRange) { - const declaration = _node.declaration - - if (declaration.start <= start && declaration.end >= end) { - const init = declaration.init - if (init.start <= start && init.end >= end) { - path.push(['declaration', 'VariableDeclaration']) - path.push(['init', '']) - return moreNodePathFromSourceRange(init, sourceRange, path) - } - } - return path - } - if (_node.type === 'UnaryExpression' && isInRange) { - const { argument } = _node - if (argument.start <= start && argument.end >= end) { - path.push(['argument', 'UnaryExpression']) - return moreNodePathFromSourceRange(argument, sourceRange, path) - } - return path - } - if (_node.type === 'FunctionExpression' && isInRange) { - for (let i = 0; i < _node.params.length; i++) { - const param = _node.params[i] - if (param.identifier.start <= start && param.identifier.end >= end) { - path.push(['params', 'FunctionExpression']) - path.push([i, 'index']) - return moreNodePathFromSourceRange(param.identifier, sourceRange, path) - } - } - if (_node.body.start <= start && _node.body.end >= end) { - path.push(['body', 'FunctionExpression']) - const fnBody = _node.body.body - for (let i = 0; i < fnBody.length; i++) { - const statement = fnBody[i] - if (statement.start <= start && statement.end >= end) { - path.push(['body', 'FunctionExpression']) - path.push([i, 'index']) - return moreNodePathFromSourceRange(statement, sourceRange, path) - } - } - } - return path - } - if (_node.type === 'ReturnStatement' && isInRange) { - const { argument } = _node - if (argument.start <= start && argument.end >= end) { - path.push(['argument', 'ReturnStatement']) - return moreNodePathFromSourceRange(argument, sourceRange, path) - } - return path - } - if (_node.type === 'MemberExpression' && isInRange) { - const { object, property } = _node - if (object.start <= start && object.end >= end) { - path.push(['object', 'MemberExpression']) - return moreNodePathFromSourceRange(object, sourceRange, path) - } - if (property.start <= start && property.end >= end) { - path.push(['property', 'MemberExpression']) - return moreNodePathFromSourceRange(property, sourceRange, path) - } - return path - } - - if (_node.type === 'PipeSubstitution' && isInRange) return path - - if (_node.type === 'IfExpression' && isInRange) { - const { cond, then_val, else_ifs, final_else } = _node - if (cond.start <= start && cond.end >= end) { - path.push(['cond', 'IfExpression']) - return moreNodePathFromSourceRange(cond, sourceRange, path) - } - if (then_val.start <= start && then_val.end >= end) { - path.push(['then_val', 'IfExpression']) - path.push(['body', 'IfExpression']) - return getNodePathFromSourceRange(then_val, sourceRange, path) - } - for (let i = 0; i < else_ifs.length; i++) { - const else_if = else_ifs[i] - if (else_if.start <= start && else_if.end >= end) { - path.push(['else_ifs', 'IfExpression']) - path.push([i, 'index']) - const { cond, then_val } = else_if - if (cond.start <= start && cond.end >= end) { - path.push(['cond', 'IfExpression']) - return moreNodePathFromSourceRange(cond, sourceRange, path) - } - path.push(['then_val', 'IfExpression']) - path.push(['body', 'IfExpression']) - return getNodePathFromSourceRange(then_val, sourceRange, path) - } - } - if (final_else.start <= start && final_else.end >= end) { - path.push(['final_else', 'IfExpression']) - path.push(['body', 'IfExpression']) - return getNodePathFromSourceRange(final_else, sourceRange, path) - } - return path - } - - if (_node.type === 'ImportStatement' && isInRange) { - if (_node.selector && _node.selector.type === 'List') { - path.push(['selector', 'ImportStatement']) - const { items } = _node.selector - for (let i = 0; i < items.length; i++) { - const item = items[i] - if (item.start <= start && item.end >= end) { - path.push(['items', 'ImportSelector']) - path.push([i, 'index']) - if (item.name.start <= start && item.name.end >= end) { - path.push(['name', 'ImportItem']) - return path - } - if ( - item.alias && - item.alias.start <= start && - item.alias.end >= end - ) { - path.push(['alias', 'ImportItem']) - return path - } - return path - } - } - return path - } - return path - } - - console.error('not implemented: ' + node.type) - - return path -} - -export function getNodePathFromSourceRange( - node: Program, - sourceRange: SourceRange, - previousPath: PathToNode = [['body', '']] -): PathToNode { - const [start, end] = sourceRange || [] - let path: PathToNode = [...previousPath] - const _node = { ...node } - - // loop over each statement in body getting the index with a for loop - for ( - let statementIndex = 0; - statementIndex < _node.body.length; - statementIndex++ - ) { - const statement = _node.body[statementIndex] - if (statement.start <= start && statement.end >= end) { - path.push([statementIndex, 'index']) - return moreNodePathFromSourceRange(statement, sourceRange, path) - } - } - return path -} - type KCLNode = Node< | Expr | ExpressionStatement diff --git a/src/lang/queryAstNodePathUtils.ts b/src/lang/queryAstNodePathUtils.ts new file mode 100644 index 000000000..200f6f6d8 --- /dev/null +++ b/src/lang/queryAstNodePathUtils.ts @@ -0,0 +1,316 @@ +import { + Expr, + ExpressionStatement, + VariableDeclaration, + ReturnStatement, + SourceRange, + PathToNode, + Program, +} from './wasm' +import { ImportStatement } from 'wasm-lib/kcl/bindings/ImportStatement' +import { Node } from 'wasm-lib/kcl/bindings/Node' + +function moreNodePathFromSourceRange( + node: Node< + | Expr + | ImportStatement + | ExpressionStatement + | VariableDeclaration + | ReturnStatement + >, + sourceRange: SourceRange, + previousPath: PathToNode = [['body', '']] +): PathToNode { + const [start, end] = sourceRange + let path: PathToNode = [...previousPath] + const _node = { ...node } + + if (start < _node.start || end > _node.end) return path + + const isInRange = _node.start <= start && _node.end >= end + + if ( + (_node.type === 'Identifier' || + _node.type === 'Literal' || + _node.type === 'TagDeclarator') && + isInRange + ) { + return path + } + + if (_node.type === 'CallExpression' && isInRange) { + const { callee, arguments: args } = _node + if ( + callee.type === 'Identifier' && + callee.start <= start && + callee.end >= end + ) { + path.push(['callee', 'CallExpression']) + return path + } + if (args.length > 0) { + for (let argIndex = 0; argIndex < args.length; argIndex++) { + const arg = args[argIndex] + if (arg.start <= start && arg.end >= end) { + path.push(['arguments', 'CallExpression']) + path.push([argIndex, 'index']) + return moreNodePathFromSourceRange(arg, sourceRange, path) + } + } + } + return path + } + + if (_node.type === 'CallExpressionKw' && isInRange) { + const { callee, arguments: args } = _node + if ( + callee.type === 'Identifier' && + callee.start <= start && + callee.end >= end + ) { + path.push(['callee', 'CallExpressionKw']) + return path + } + if (args.length > 0) { + for (let argIndex = 0; argIndex < args.length; argIndex++) { + const arg = args[argIndex].arg + if (arg.start <= start && arg.end >= end) { + path.push(['arguments', 'CallExpressionKw']) + path.push([argIndex, 'index']) + return moreNodePathFromSourceRange(arg, sourceRange, path) + } + } + } + return path + } + + if (_node.type === 'BinaryExpression' && isInRange) { + const { left, right } = _node + if (left.start <= start && left.end >= end) { + path.push(['left', 'BinaryExpression']) + return moreNodePathFromSourceRange(left, sourceRange, path) + } + if (right.start <= start && right.end >= end) { + path.push(['right', 'BinaryExpression']) + return moreNodePathFromSourceRange(right, sourceRange, path) + } + return path + } + if (_node.type === 'PipeExpression' && isInRange) { + const { body } = _node + for (let i = 0; i < body.length; i++) { + const pipe = body[i] + if (pipe.start <= start && pipe.end >= end) { + path.push(['body', 'PipeExpression']) + path.push([i, 'index']) + return moreNodePathFromSourceRange(pipe, sourceRange, path) + } + } + return path + } + if (_node.type === 'ArrayExpression' && isInRange) { + const { elements } = _node + for (let elIndex = 0; elIndex < elements.length; elIndex++) { + const element = elements[elIndex] + if (element.start <= start && element.end >= end) { + path.push(['elements', 'ArrayExpression']) + path.push([elIndex, 'index']) + return moreNodePathFromSourceRange(element, sourceRange, path) + } + } + return path + } + if (_node.type === 'ObjectExpression' && isInRange) { + const { properties } = _node + for (let propIndex = 0; propIndex < properties.length; propIndex++) { + const property = properties[propIndex] + if (property.start <= start && property.end >= end) { + path.push(['properties', 'ObjectExpression']) + path.push([propIndex, 'index']) + if (property.key.start <= start && property.key.end >= end) { + path.push(['key', 'Property']) + return moreNodePathFromSourceRange(property.key, sourceRange, path) + } + if (property.value.start <= start && property.value.end >= end) { + path.push(['value', 'Property']) + return moreNodePathFromSourceRange(property.value, sourceRange, path) + } + } + } + return path + } + if (_node.type === 'ExpressionStatement' && isInRange) { + const { expression } = _node + path.push(['expression', 'ExpressionStatement']) + return moreNodePathFromSourceRange(expression, sourceRange, path) + } + if (_node.type === 'VariableDeclaration' && isInRange) { + const declaration = _node.declaration + + if (declaration.start <= start && declaration.end >= end) { + path.push(['declaration', 'VariableDeclaration']) + const init = declaration.init + if (init.start <= start && init.end >= end) { + path.push(['init', '']) + return moreNodePathFromSourceRange(init, sourceRange, path) + } + } + } + if (_node.type === 'VariableDeclaration' && isInRange) { + const declaration = _node.declaration + + if (declaration.start <= start && declaration.end >= end) { + const init = declaration.init + if (init.start <= start && init.end >= end) { + path.push(['declaration', 'VariableDeclaration']) + path.push(['init', '']) + return moreNodePathFromSourceRange(init, sourceRange, path) + } + } + return path + } + if (_node.type === 'UnaryExpression' && isInRange) { + const { argument } = _node + if (argument.start <= start && argument.end >= end) { + path.push(['argument', 'UnaryExpression']) + return moreNodePathFromSourceRange(argument, sourceRange, path) + } + return path + } + if (_node.type === 'FunctionExpression' && isInRange) { + for (let i = 0; i < _node.params.length; i++) { + const param = _node.params[i] + if (param.identifier.start <= start && param.identifier.end >= end) { + path.push(['params', 'FunctionExpression']) + path.push([i, 'index']) + return moreNodePathFromSourceRange(param.identifier, sourceRange, path) + } + } + if (_node.body.start <= start && _node.body.end >= end) { + path.push(['body', 'FunctionExpression']) + const fnBody = _node.body.body + for (let i = 0; i < fnBody.length; i++) { + const statement = fnBody[i] + if (statement.start <= start && statement.end >= end) { + path.push(['body', 'FunctionExpression']) + path.push([i, 'index']) + return moreNodePathFromSourceRange(statement, sourceRange, path) + } + } + } + return path + } + if (_node.type === 'ReturnStatement' && isInRange) { + const { argument } = _node + if (argument.start <= start && argument.end >= end) { + path.push(['argument', 'ReturnStatement']) + return moreNodePathFromSourceRange(argument, sourceRange, path) + } + return path + } + if (_node.type === 'MemberExpression' && isInRange) { + const { object, property } = _node + if (object.start <= start && object.end >= end) { + path.push(['object', 'MemberExpression']) + return moreNodePathFromSourceRange(object, sourceRange, path) + } + if (property.start <= start && property.end >= end) { + path.push(['property', 'MemberExpression']) + return moreNodePathFromSourceRange(property, sourceRange, path) + } + return path + } + + if (_node.type === 'PipeSubstitution' && isInRange) return path + + if (_node.type === 'IfExpression' && isInRange) { + const { cond, then_val, else_ifs, final_else } = _node + if (cond.start <= start && cond.end >= end) { + path.push(['cond', 'IfExpression']) + return moreNodePathFromSourceRange(cond, sourceRange, path) + } + if (then_val.start <= start && then_val.end >= end) { + path.push(['then_val', 'IfExpression']) + path.push(['body', 'IfExpression']) + return getNodePathFromSourceRange(then_val, sourceRange, path) + } + for (let i = 0; i < else_ifs.length; i++) { + const else_if = else_ifs[i] + if (else_if.start <= start && else_if.end >= end) { + path.push(['else_ifs', 'IfExpression']) + path.push([i, 'index']) + const { cond, then_val } = else_if + if (cond.start <= start && cond.end >= end) { + path.push(['cond', 'IfExpression']) + return moreNodePathFromSourceRange(cond, sourceRange, path) + } + path.push(['then_val', 'IfExpression']) + path.push(['body', 'IfExpression']) + return getNodePathFromSourceRange(then_val, sourceRange, path) + } + } + if (final_else.start <= start && final_else.end >= end) { + path.push(['final_else', 'IfExpression']) + path.push(['body', 'IfExpression']) + return getNodePathFromSourceRange(final_else, sourceRange, path) + } + return path + } + + if (_node.type === 'ImportStatement' && isInRange) { + if (_node.selector && _node.selector.type === 'List') { + path.push(['selector', 'ImportStatement']) + const { items } = _node.selector + for (let i = 0; i < items.length; i++) { + const item = items[i] + if (item.start <= start && item.end >= end) { + path.push(['items', 'ImportSelector']) + path.push([i, 'index']) + if (item.name.start <= start && item.name.end >= end) { + path.push(['name', 'ImportItem']) + return path + } + if ( + item.alias && + item.alias.start <= start && + item.alias.end >= end + ) { + path.push(['alias', 'ImportItem']) + return path + } + return path + } + } + return path + } + return path + } + + console.error('not implemented: ' + node.type) + + return path +} + +export function getNodePathFromSourceRange( + node: Program, + sourceRange: SourceRange, + previousPath: PathToNode = [['body', '']] +): PathToNode { + const [start, end] = sourceRange || [] + let path: PathToNode = [...previousPath] + const _node = { ...node } + + // loop over each statement in body getting the index with a for loop + for ( + let statementIndex = 0; + statementIndex < _node.body.length; + statementIndex++ + ) { + const statement = _node.body[statementIndex] + if (statement.start <= start && statement.end >= end) { + path.push([statementIndex, 'index']) + return moreNodePathFromSourceRange(statement, sourceRange, path) + } + } + return path +} diff --git a/src/lang/std/artifactGraph.ts b/src/lang/std/artifactGraph.ts index 879203d18..4bad2cf64 100644 --- a/src/lang/std/artifactGraph.ts +++ b/src/lang/std/artifactGraph.ts @@ -16,7 +16,7 @@ import { EdgeCut, } from 'lang/wasm' import { Models } from '@kittycad/lib' -import { getNodePathFromSourceRange } from 'lang/queryAst' +import { getNodePathFromSourceRange } from 'lang/queryAstNodePathUtils' import { err } from 'lib/trap' export type { Artifact, ArtifactId, SegmentArtifact } from 'lang/wasm' diff --git a/src/lang/std/sketch.test.ts b/src/lang/std/sketch.test.ts index 5c631666d..c1054a7c0 100644 --- a/src/lang/std/sketch.test.ts +++ b/src/lang/std/sketch.test.ts @@ -14,7 +14,8 @@ import { CallExpression, topLevelRange, } from '../wasm' -import { getNodeFromPath, getNodePathFromSourceRange } from '../queryAst' +import { getNodeFromPath } from '../queryAst' +import { getNodePathFromSourceRange } from 'lang/queryAstNodePathUtils' import { enginelessExecutor } from '../../lib/testHelpers' import { err } from 'lib/trap' import { Node } from 'wasm-lib/kcl/bindings/Node' diff --git a/src/lang/std/sketch.ts b/src/lang/std/sketch.ts index 136edbd58..2119ae153 100644 --- a/src/lang/std/sketch.ts +++ b/src/lang/std/sketch.ts @@ -17,9 +17,9 @@ import { import { getNodeFromPath, getNodeFromPathCurry, - getNodePathFromSourceRange, getObjExprProperty, } from 'lang/queryAst' +import { getNodePathFromSourceRange } from 'lang/queryAstNodePathUtils' import { isLiteralArrayOrStatic, isNotLiteralArrayOrStatic, diff --git a/src/lang/std/sketchcombos.ts b/src/lang/std/sketchcombos.ts index fd92f9d2d..12acb288d 100644 --- a/src/lang/std/sketchcombos.ts +++ b/src/lang/std/sketchcombos.ts @@ -22,11 +22,8 @@ import { SourceRange, LiteralValue, } from '../wasm' -import { - getNodeFromPath, - getNodeFromPathCurry, - getNodePathFromSourceRange, -} from '../queryAst' +import { getNodeFromPath, getNodeFromPathCurry } from '../queryAst' +import { getNodePathFromSourceRange } from 'lang/queryAstNodePathUtils' import { createArrayExpression, createBinaryExpression, diff --git a/src/lang/wasm.ts b/src/lang/wasm.ts index b1eb7621f..cdb5764de 100644 --- a/src/lang/wasm.ts +++ b/src/lang/wasm.ts @@ -53,7 +53,7 @@ import { ArtifactId } from 'wasm-lib/kcl/bindings/Artifact' import { ArtifactCommand } from 'wasm-lib/kcl/bindings/Artifact' import { ArtifactGraph as RustArtifactGraph } from 'wasm-lib/kcl/bindings/Artifact' import { Artifact } from './std/artifactGraph' -import { getNodePathFromSourceRange } from './queryAst' +import { getNodePathFromSourceRange } from 'lang/queryAstNodePathUtils' export type { Artifact } from 'wasm-lib/kcl/bindings/Artifact' export type { ArtifactCommand } from 'wasm-lib/kcl/bindings/Artifact' diff --git a/src/lib/selections.ts b/src/lib/selections.ts index 9b4c4ddba..76dcd53f4 100644 --- a/src/lib/selections.ts +++ b/src/lib/selections.ts @@ -18,11 +18,8 @@ import { EditorSelection, SelectionRange } from '@codemirror/state' import { getNormalisedCoordinates, isOverlap } from 'lib/utils' import { isCursorInSketchCommandRange } from 'lang/util' import { Program } from 'lang/wasm' -import { - getNodeFromPath, - getNodePathFromSourceRange, - isSingleCursorInPipe, -} from 'lang/queryAst' +import { getNodeFromPath, isSingleCursorInPipe } from 'lang/queryAst' +import { getNodePathFromSourceRange } from 'lang/queryAstNodePathUtils' import { CommandArgument } from './commandTypes' import { DefaultPlaneStr, diff --git a/src/machines/modelingMachine.ts b/src/machines/modelingMachine.ts index 6ea012a96..596bf7aee 100644 --- a/src/machines/modelingMachine.ts +++ b/src/machines/modelingMachine.ts @@ -16,10 +16,8 @@ import { } from 'lib/selections' import { assign, fromPromise, fromCallback, setup } from 'xstate' import { SidebarType } from 'components/ModelingSidebar/ModelingPanes' -import { - isNodeSafeToReplacePath, - getNodePathFromSourceRange, -} from 'lang/queryAst' +import { isNodeSafeToReplacePath } from 'lang/queryAst' +import { getNodePathFromSourceRange } from 'lang/queryAstNodePathUtils' import { kclManager, sceneInfra,