From 39eefa86d881b70831e4faf06c576b761473607d Mon Sep 17 00:00:00 2001 From: max-mrgrsk <156543465+max-mrgrsk@users.noreply.github.com> Date: Tue, 1 Oct 2024 13:39:04 +0200 Subject: [PATCH 1/6] combine tags + tests --- src/lang/modifyAst/addFillet.test.ts | 341 +++++------------- src/lang/modifyAst/addFillet.ts | 265 ++++++-------- .../modelingCommandConfig.ts | 7 +- 3 files changed, 198 insertions(+), 415 deletions(-) diff --git a/src/lang/modifyAst/addFillet.test.ts b/src/lang/modifyAst/addFillet.test.ts index f23d687371..e30221ab30 100644 --- a/src/lang/modifyAst/addFillet.test.ts +++ b/src/lang/modifyAst/addFillet.test.ts @@ -10,11 +10,10 @@ import { VariableDeclaration, } from '../wasm' import { - addFillet, getPathToExtrudeForSegmentSelection, hasValidFilletSelection, isTagUsedInFillet, - modifyAstWithFilletAndTag, + modifyAstCloneWithFilletAndTag, } from './addFillet' import { getNodeFromPath, getNodePathFromSourceRange } from '../queryAst' import { createLiteral } from 'lang/modifyAst' @@ -116,16 +115,14 @@ const runGetPathToExtrudeForSegmentSelectionTest = async ( otherSelections: [], } - // programMemory and artifactGraph + // executeAst and artifactGraph await kclManager.executeAst({ ast }) - const programMemory = kclManager.programMemory const artifactGraph = engineCommandManager.artifactGraph // get extrude expression const pathResult = getPathToExtrudeForSegmentSelection( ast, selection, - programMemory, artifactGraph ) if (err(pathResult)) return pathResult @@ -230,226 +227,7 @@ const extrude003 = extrude(-15, sketch003)` }) }) -const runFilletTest = async ( - code: string, - segmentSnippet: string, - extrudeSnippet: string, - radius = createLiteral(5), - expectedCode: string -) => { - const astOrError = parse(code) - if (err(astOrError)) { - return new Error('AST not found') - } - - const ast = astOrError - - const segmentRange: [number, number] = [ - code.indexOf(segmentSnippet), - code.indexOf(segmentSnippet) + segmentSnippet.length, - ] - const pathToSegmentNode: PathToNode = getNodePathFromSourceRange( - ast, - segmentRange - ) - - const extrudeRange: [number, number] = [ - code.indexOf(extrudeSnippet), - code.indexOf(extrudeSnippet) + extrudeSnippet.length, - ] - - const pathToExtrudeNode: PathToNode = getNodePathFromSourceRange( - ast, - extrudeRange - ) - if (err(pathToExtrudeNode)) { - return new Error('Path to extrude node not found') - } - - const result = addFillet(ast, pathToSegmentNode, pathToExtrudeNode, radius) - if (err(result)) { - return result - } - const { modifiedAst } = result - const newCode = recast(modifiedAst) - - expect(newCode).toContain(expectedCode) -} -describe('Testing addFillet', () => { - /** - * 1. Ideal Case - */ - - it('should add a fillet to a specific segment after extrusion, clean', async () => { - const code = ` - const sketch001 = startSketchOn('XZ') - |> startProfileAt([2.16, 49.67], %) - |> line([101.49, 139.93], %) - |> line([60.04, -55.72], %) - |> line([1.29, -115.74], %) - |> line([-87.24, -47.08], %) - |> tangentialArcTo([56.15, -94.58], %) - |> tangentialArcTo([14.68, -104.52], %) - |> lineTo([profileStartX(%), profileStartY(%)], %) - |> close(%) - const extrude001 = extrude(50, sketch001) - ` - const segmentSnippet = `line([60.04, -55.72], %)` - const extrudeSnippet = `const extrude001 = extrude(50, sketch001)` - const radius = createLiteral(5) - const expectedCode = `const sketch001 = startSketchOn('XZ') - |> startProfileAt([2.16, 49.67], %) - |> line([101.49, 139.93], %) - |> line([60.04, -55.72], %, $seg01) - |> line([1.29, -115.74], %) - |> line([-87.24, -47.08], %) - |> tangentialArcTo([56.15, -94.58], %) - |> tangentialArcTo([14.68, -104.52], %) - |> lineTo([profileStartX(%), profileStartY(%)], %) - |> close(%) -const extrude001 = extrude(50, sketch001) - |> fillet({ radius: 5, tags: [seg01] }, %)` - - await runFilletTest( - code, - segmentSnippet, - extrudeSnippet, - radius, - expectedCode - ) - }) - - /** - * 2. Case of existing tag in the other line - */ - - it('should add a fillet to a specific segment after extrusion with existing tag in any other line', async () => { - const code = ` - const sketch001 = startSketchOn('XZ') - |> startProfileAt([2.16, 49.67], %) - |> line([101.49, 139.93], %) - |> line([60.04, -55.72], %) - |> line([1.29, -115.74], %) - |> line([-87.24, -47.08], %, $seg01) - |> tangentialArcTo([56.15, -94.58], %) - |> tangentialArcTo([14.68, -104.52], %) - |> lineTo([profileStartX(%), profileStartY(%)], %) - |> close(%) - const extrude001 = extrude(50, sketch001) - ` - const segmentSnippet = `line([60.04, -55.72], %)` - const extrudeSnippet = `const extrude001 = extrude(50, sketch001)` - const radius = createLiteral(5) - const expectedCode = `const sketch001 = startSketchOn('XZ') - |> startProfileAt([2.16, 49.67], %) - |> line([101.49, 139.93], %) - |> line([60.04, -55.72], %, $seg02) - |> line([1.29, -115.74], %) - |> line([-87.24, -47.08], %, $seg01) - |> tangentialArcTo([56.15, -94.58], %) - |> tangentialArcTo([14.68, -104.52], %) - |> lineTo([profileStartX(%), profileStartY(%)], %) - |> close(%) -const extrude001 = extrude(50, sketch001) - |> fillet({ radius: 5, tags: [seg02] }, %)` - - await runFilletTest( - code, - segmentSnippet, - extrudeSnippet, - radius, - expectedCode - ) - }) - - /** - * 3. Case of existing tag in the fillet line - */ - - it('should add a fillet to a specific segment after extrusion with existing tag in that exact line', async () => { - const code = ` - const sketch001 = startSketchOn('XZ') - |> startProfileAt([2.16, 49.67], %) - |> line([101.49, 139.93], %) - |> line([60.04, -55.72], %) - |> line([1.29, -115.74], %) - |> line([-87.24, -47.08], %, $seg03) - |> tangentialArcTo([56.15, -94.58], %) - |> tangentialArcTo([14.68, -104.52], %) - |> lineTo([profileStartX(%), profileStartY(%)], %) - |> close(%) - const extrude001 = extrude(50, sketch001) - ` - const segmentSnippet = `line([-87.24, -47.08], %, $seg03)` - const extrudeSnippet = `const extrude001 = extrude(50, sketch001)` - const radius = createLiteral(5) - const expectedCode = `const sketch001 = startSketchOn('XZ') - |> startProfileAt([2.16, 49.67], %) - |> line([101.49, 139.93], %) - |> line([60.04, -55.72], %) - |> line([1.29, -115.74], %) - |> line([-87.24, -47.08], %, $seg03) - |> tangentialArcTo([56.15, -94.58], %) - |> tangentialArcTo([14.68, -104.52], %) - |> lineTo([profileStartX(%), profileStartY(%)], %) - |> close(%) -const extrude001 = extrude(50, sketch001) - |> fillet({ radius: 5, tags: [seg03] }, %)` - - await runFilletTest( - code, - segmentSnippet, - extrudeSnippet, - radius, - expectedCode - ) - }) - - /** - * 4. Case of existing fillet on some other segment - */ - - it('should add another fillet after the existing fillet', async () => { - const code = `const sketch001 = startSketchOn('XZ') - |> startProfileAt([2.16, 49.67], %) - |> line([101.49, 139.93], %) - |> line([60.04, -55.72], %) - |> line([1.29, -115.74], %) - |> line([-87.24, -47.08], %, $seg03) - |> tangentialArcTo([56.15, -94.58], %) - |> tangentialArcTo([14.68, -104.52], %) - |> lineTo([profileStartX(%), profileStartY(%)], %) - |> close(%) - const extrude001 = extrude(50, sketch001) - |> fillet({ radius: 10, tags: [seg03] }, %)` - const segmentSnippet = `line([60.04, -55.72], %)` - const extrudeSnippet = `const extrude001 = extrude(50, sketch001)` - const radius = createLiteral(5) - const expectedCode = `const sketch001 = startSketchOn('XZ') - |> startProfileAt([2.16, 49.67], %) - |> line([101.49, 139.93], %) - |> line([60.04, -55.72], %, $seg01) - |> line([1.29, -115.74], %) - |> line([-87.24, -47.08], %, $seg03) - |> tangentialArcTo([56.15, -94.58], %) - |> tangentialArcTo([14.68, -104.52], %) - |> lineTo([profileStartX(%), profileStartY(%)], %) - |> close(%) -const extrude001 = extrude(50, sketch001) - |> fillet({ radius: 10, tags: [seg03] }, %) - |> fillet({ radius: 5, tags: [seg01] }, %)` - - await runFilletTest( - code, - segmentSnippet, - extrudeSnippet, - radius, - expectedCode - ) - }) -}) - -const runModifyAstWithFilletAndTagTest = async ( +const runModifyAstCloneWithFilletAndTag = async ( code: string, selectionSnippets: Array, radiusValue: number, @@ -484,11 +262,11 @@ const runModifyAstWithFilletAndTagTest = async ( valueCalculated: radiusValue.toString(), } - // programMemory and artifactGraph + // executeAst await kclManager.executeAst({ ast }) // apply fillet to selection - const result = modifyAstWithFilletAndTag(ast, selection, radius) + const result = modifyAstCloneWithFilletAndTag(ast, selection, radius) if (err(result)) { return result } @@ -499,7 +277,7 @@ const runModifyAstWithFilletAndTagTest = async ( expect(newCode).toContain(expectedCode) } describe('Testing applyFilletToSelection', () => { - it('should add a fillet to a specific segment after extrusion', async () => { + it('should add a fillet to a specific segment', async () => { const code = `const sketch001 = startSketchOn('XY') |> startProfileAt([-10, 10], %) |> line([20, 0], %) @@ -520,23 +298,51 @@ const extrude001 = extrude(-15, sketch001)` const extrude001 = extrude(-15, sketch001) |> fillet({ radius: 3, tags: [seg01] }, %)` - await runModifyAstWithFilletAndTagTest( + await runModifyAstCloneWithFilletAndTag( code, segmentSnippets, radiusValue, expectedCode ) }) - it('should add a fillet to the 2 segments of a single extrusion', async () => { + it('should add a fillet to an already tagged segment', async () => { const code = `const sketch001 = startSketchOn('XY') |> startProfileAt([-10, 10], %) |> line([20, 0], %) + |> line([0, -20], %, $seg01) + |> line([-20, 0], %) + |> lineTo([profileStartX(%), profileStartY(%)], %) + |> close(%) +const extrude001 = extrude(-15, sketch001)` + const segmentSnippets = ['line([0, -20], %, $seg01)'] + const radiusValue = 3 + const expectedCode = `const sketch001 = startSketchOn('XY') + |> startProfileAt([-10, 10], %) + |> line([20, 0], %) + |> line([0, -20], %, $seg01) + |> line([-20, 0], %) + |> lineTo([profileStartX(%), profileStartY(%)], %) + |> close(%) +const extrude001 = extrude(-15, sketch001) + |> fillet({ radius: 3, tags: [seg01] }, %)` + + await runModifyAstCloneWithFilletAndTag( + code, + segmentSnippets, + radiusValue, + expectedCode + ) + }) + it('should add a fillet with existing tag on other segment', async () => { + const code = `const sketch001 = startSketchOn('XY') + |> startProfileAt([-10, 10], %) + |> line([20, 0], %, $seg01) |> line([0, -20], %) |> line([-20, 0], %) |> lineTo([profileStartX(%), profileStartY(%)], %) |> close(%) const extrude001 = extrude(-15, sketch001)` - const segmentSnippets = ['line([20, 0], %)', 'line([-20, 0], %)'] + const segmentSnippets = ['line([-20, 0], %)'] const radiusValue = 3 const expectedCode = `const sketch001 = startSketchOn('XY') |> startProfileAt([-10, 10], %) @@ -546,47 +352,74 @@ const extrude001 = extrude(-15, sketch001)` |> lineTo([profileStartX(%), profileStartY(%)], %) |> close(%) const extrude001 = extrude(-15, sketch001) - |> fillet({ radius: 3, tags: [seg01] }, %) |> fillet({ radius: 3, tags: [seg02] }, %)` - await runModifyAstWithFilletAndTagTest( + await runModifyAstCloneWithFilletAndTag( code, segmentSnippets, radiusValue, expectedCode ) }) - it('should add a fillet when the extrude variable previously had an fillet', async () => { + it('should add a fillet with existing fillet on other segment', async () => { const code = `const sketch001 = startSketchOn('XY') |> startProfileAt([-10, 10], %) - |> line([20, 0], %) + |> line([20, 0], %, $seg01) + |> line([0, -20], %) + |> line([-20, 0], %) + |> lineTo([profileStartX(%), profileStartY(%)], %) + |> close(%) +const extrude001 = extrude(-15, sketch001) + |> fillet({ radius: 5, tags: [seg01] }, %)` + const segmentSnippets = ['line([-20, 0], %)'] + const radiusValue = 3 + const expectedCode = `const sketch001 = startSketchOn('XY') + |> startProfileAt([-10, 10], %) + |> line([20, 0], %, $seg01) |> line([0, -20], %) - |> line([-20, 0], %, $seg01) + |> line([-20, 0], %, $seg02) |> lineTo([profileStartX(%), profileStartY(%)], %) |> close(%) const extrude001 = extrude(-15, sketch001) - |> fillet({ radius: 3, tags: [seg01] }, %)` // <--- one fillet already there on input code - const segmentSnippets = ['line([20, 0], %)'] + |> fillet({ radius: 5, tags: [seg01] }, %) + |> fillet({ radius: 3, tags: [seg02] }, %)` + + await runModifyAstCloneWithFilletAndTag( + code, + segmentSnippets, + radiusValue, + expectedCode + ) + }) + it('should add a fillet to two segments of a single extrusion', async () => { + const code = `const sketch001 = startSketchOn('XY') + |> startProfileAt([-10, 10], %) + |> line([20, 0], %) + |> line([0, -20], %) + |> line([-20, 0], %) + |> lineTo([profileStartX(%), profileStartY(%)], %) + |> close(%) +const extrude001 = extrude(-15, sketch001)` + const segmentSnippets = ['line([20, 0], %)', 'line([-20, 0], %)'] const radiusValue = 3 const expectedCode = `const sketch001 = startSketchOn('XY') |> startProfileAt([-10, 10], %) - |> line([20, 0], %, $seg02) + |> line([20, 0], %, $seg01) |> line([0, -20], %) - |> line([-20, 0], %, $seg01) + |> line([-20, 0], %, $seg02) |> lineTo([profileStartX(%), profileStartY(%)], %) |> close(%) const extrude001 = extrude(-15, sketch001) - |> fillet({ radius: 3, tags: [seg01] }, %) - |> fillet({ radius: 3, tags: [seg02] }, %)` // <-- able to add a new one + |> fillet({ radius: 3, tags: [seg01, seg02] }, %)` - await runModifyAstWithFilletAndTagTest( + await runModifyAstCloneWithFilletAndTag( code, segmentSnippets, radiusValue, expectedCode ) }) - it('should add the fillets to 2 bodies', async () => { + it('should add fillets to two bodies', async () => { const code = `const sketch001 = startSketchOn('XY') |> startProfileAt([-10, 10], %) |> line([20, 0], %) @@ -603,28 +436,32 @@ const sketch002 = startSketchOn('XY') |> lineTo([profileStartX(%), profileStartY(%)], %) |> close(%) const extrude002 = extrude(-25, sketch002)` // <--- body 2 - const segmentSnippets = ['line([0, -20], %)', 'line([0, -15], %)'] + const segmentSnippets = [ + 'line([20, 0], %)', + 'line([-20, 0], %)', + 'line([0, -15], %)', + ] const radiusValue = 3 const expectedCode = `const sketch001 = startSketchOn('XY') |> startProfileAt([-10, 10], %) - |> line([20, 0], %) - |> line([0, -20], %, $seg01) - |> line([-20, 0], %) + |> line([20, 0], %, $seg01) + |> line([0, -20], %) + |> line([-20, 0], %, $seg02) |> lineTo([profileStartX(%), profileStartY(%)], %) |> close(%) const extrude001 = extrude(-15, sketch001) - |> fillet({ radius: 3, tags: [seg01] }, %) + |> fillet({ radius: 3, tags: [seg01, seg02] }, %) const sketch002 = startSketchOn('XY') |> startProfileAt([30, 10], %) |> line([15, 0], %) - |> line([0, -15], %, $seg02) + |> line([0, -15], %, $seg03) |> line([-15, 0], %) |> lineTo([profileStartX(%), profileStartY(%)], %) |> close(%) const extrude002 = extrude(-25, sketch002) - |> fillet({ radius: 3, tags: [seg02] }, %)` // <-- able to add a new one + |> fillet({ radius: 3, tags: [seg03] }, %)` // <-- able to add a new one - await runModifyAstWithFilletAndTagTest( + await runModifyAstCloneWithFilletAndTag( code, segmentSnippets, radiusValue, diff --git a/src/lang/modifyAst/addFillet.ts b/src/lang/modifyAst/addFillet.ts index cd6eccad03..2efe5381fe 100644 --- a/src/lang/modifyAst/addFillet.ts +++ b/src/lang/modifyAst/addFillet.ts @@ -4,15 +4,12 @@ import { ObjectExpression, PathToNode, Program, - ProgramMemory, - Expr, VariableDeclaration, VariableDeclarator, sketchFromKclValue, } from '../wasm' import { createCallExpressionStdLib, - createLiteral, createPipeSubstitution, createObjectExpression, createArrayExpression, @@ -39,70 +36,142 @@ import { } from 'lang/std/artifactGraph' import { kclManager, engineCommandManager, editorManager } from 'lib/singletons' -/** - * Apply Fillet To Selection - */ +// Apply Fillet To Selection export function applyFilletToSelection( ast: Program, selection: Selections, radius: KclCommandValue ): void | Error { - // 1. clone ast - let clonedAst = structuredClone(ast) - - // 2. modify ast clone with fillet and tag - const result = modifyAstWithFilletAndTag(clonedAst, selection, radius) + // 1. clone and modify with fillet and tag + const result = modifyAstCloneWithFilletAndTag(ast, selection, radius) if (err(result)) return result const { modifiedAst, pathToFilletNode } = result - // 3. update ast + // 2. update ast // eslint-disable-next-line @typescript-eslint/no-floating-promises updateAstAndFocus(modifiedAst, pathToFilletNode) } -export function modifyAstWithFilletAndTag( +export function modifyAstCloneWithFilletAndTag( ast: Program, selection: Selections, radius: KclCommandValue ): { modifiedAst: Program; pathToFilletNode: Array } | Error { - const astResult = insertRadiusIntoAst(ast, radius) + let clonedAst = structuredClone(ast) + const clonedAstForGetExtrude = structuredClone(ast) + + const astResult = insertRadiusIntoAst(clonedAst, radius) if (err(astResult)) return astResult - const programMemory = kclManager.programMemory const artifactGraph = engineCommandManager.artifactGraph - let clonedAst = structuredClone(ast) - const clonedAstForGetExtrude = structuredClone(ast) - let pathToFilletNodes: Array = [] + // Step 1: modify ast with tags and group them by extrude nodes (bodies) + const extrudeToTagsMap: Map = new Map() + const lookupMap: Map = new Map() // work around for Map key comparison for (const selectionRange of selection.codeBasedSelections) { const singleSelection = { codeBasedSelections: [selectionRange], otherSelections: [], } - const getPathToExtrudeForSegmentSelectionResult = - getPathToExtrudeForSegmentSelection( - clonedAstForGetExtrude, - singleSelection, - programMemory, - artifactGraph - ) - if (err(getPathToExtrudeForSegmentSelectionResult)) - return getPathToExtrudeForSegmentSelectionResult - const { pathToSegmentNode, pathToExtrudeNode } = - getPathToExtrudeForSegmentSelectionResult - const addFilletResult = addFillet( + const result = getPathToExtrudeForSegmentSelection( + clonedAstForGetExtrude, + singleSelection, + artifactGraph + ) + if (err(result)) return result + const { pathToSegmentNode, pathToExtrudeNode } = result + + const tagResult = mutateAstWithTagForSketchSegment( clonedAst, - pathToSegmentNode, - pathToExtrudeNode, + pathToSegmentNode + ) + if (err(tagResult)) return tagResult + const { tag } = tagResult + + // Group tags by their corresponding extrude node + const extrudeKey = JSON.stringify(pathToExtrudeNode) + + if (lookupMap.has(extrudeKey)) { + const existingPath = lookupMap.get(extrudeKey) + if (!existingPath) return new Error('Path to extrude node not found.') + extrudeToTagsMap.get(existingPath)?.push(tag) + } else { + lookupMap.set(extrudeKey, pathToExtrudeNode) + extrudeToTagsMap.set(pathToExtrudeNode, [tag]) + } + } + + // Step 2: Apply fillet(s) for each extrude node (body) + let pathToFilletNodes: Array = [] + for (const [pathToExtrudeNode, tags] of extrudeToTagsMap.entries()) { + // Create a fillet expression with multiple tags + const radiusValue = 'variableName' in radius ? radius.variableIdentifierAst : radius.valueAst + const filletCall = createCallExpressionStdLib('fillet', [ + createObjectExpression({ + radius: radiusValue, + tags: createArrayExpression(tags.map((tag) => createIdentifier(tag))), + }), + createPipeSubstitution(), + ]) + + // Locate the extrude call + const locatedExtrudeDeclarator = locateExtrudeDeclarator( + clonedAst, + pathToExtrudeNode ) - if (trap(addFilletResult)) return addFilletResult - const { modifiedAst, pathToFilletNode } = addFilletResult - clonedAst = modifiedAst - pathToFilletNodes.push(pathToFilletNode) + if (err(locatedExtrudeDeclarator)) return locatedExtrudeDeclarator + const { extrudeDeclarator } = locatedExtrudeDeclarator + + // Modify the extrude expression to include this fillet expression + // CallExpression - no fillet + // PipeExpression - fillet exists + + let pathToFilletNode: PathToNode = [] + + if (extrudeDeclarator.init.type === 'CallExpression') { + // 1. case when no fillet exists + + // modify ast with new fillet call by mutating the extrude node + extrudeDeclarator.init = createPipeExpression([ + extrudeDeclarator.init, + filletCall, + ]) + + // get path to the fillet node + pathToFilletNode = getPathToNodeOfFilletLiteral( + pathToExtrudeNode, + extrudeDeclarator, + tags[0] + ) + pathToFilletNodes.push(pathToFilletNode) + } else if (extrudeDeclarator.init.type === 'PipeExpression') { + // 2. case when fillet exists + + const existingFilletCall = extrudeDeclarator.init.body.find((node) => { + return node.type === 'CallExpression' && node.callee.name === 'fillet' + }) + + if (!existingFilletCall || existingFilletCall.type !== 'CallExpression') { + return new Error('Fillet CallExpression not found.') + } + + // mutate the extrude node with the new fillet call + extrudeDeclarator.init.body.push(filletCall) + + // get path to the fillet node + pathToFilletNode = getPathToNodeOfFilletLiteral( + pathToExtrudeNode, + extrudeDeclarator, + tags[0] + ) + pathToFilletNodes.push(pathToFilletNode) + } else { + return new Error('Unsupported extrude type.') + } } return { modifiedAst: clonedAst, pathToFilletNode: pathToFilletNodes } } @@ -131,7 +200,6 @@ function insertRadiusIntoAst( export function getPathToExtrudeForSegmentSelection( ast: Program, selection: Selections, - programMemory: ProgramMemory, artifactGraph: ArtifactGraph ): { pathToSegmentNode: PathToNode; pathToExtrudeNode: PathToNode } | Error { const pathToSegmentNode = getNodePathFromSourceRange( @@ -177,40 +245,6 @@ async function updateAstAndFocus( } } -/** - * Add Fillet - */ - -export function addFillet( - ast: Program, - pathToSegmentNode: PathToNode, - pathToExtrudeNode: PathToNode, - radius: Expr = createLiteral(5) -): { modifiedAst: Program; pathToFilletNode: PathToNode } | Error { - // Clone AST to ensure safe mutations - const astClone = structuredClone(ast) - - // Modify AST clone : TAG the sketch segment and retrieve tag - const segmentResult = mutateAstWithTagForSketchSegment( - astClone, - pathToSegmentNode - ) - if (err(segmentResult)) return segmentResult - const { tag } = segmentResult - - // Modify AST clone : Insert FILLET node and retrieve path to fillet - const filletResult = mutateAstWithFilletNode( - astClone, - pathToExtrudeNode, - radius, - tag - ) - if (err(filletResult)) return filletResult - const { pathToFilletNode } = filletResult - - return { modifiedAst: astClone, pathToFilletNode } -} - function mutateAstWithTagForSketchSegment( astClone: Program, pathToSegmentNode: PathToNode @@ -243,91 +277,6 @@ function mutateAstWithTagForSketchSegment( return { modifiedAst: astClone, tag } } -function mutateAstWithFilletNode( - astClone: Program, - pathToExtrudeNode: PathToNode, - radius: Expr, - tag: string -): { modifiedAst: Program; pathToFilletNode: PathToNode } | Error { - // Locate the extrude call - const locatedExtrudeDeclarator = locateExtrudeDeclarator( - astClone, - pathToExtrudeNode - ) - if (err(locatedExtrudeDeclarator)) return locatedExtrudeDeclarator - const { extrudeDeclarator } = locatedExtrudeDeclarator - - /** - * Prepare changes to the AST - */ - - const filletCall = createCallExpressionStdLib('fillet', [ - createObjectExpression({ - radius: radius, - tags: createArrayExpression([createIdentifier(tag)]), - }), - createPipeSubstitution(), - ]) - - /** - * Mutate the AST - */ - - // CallExpression - no fillet - // PipeExpression - fillet exists - - let pathToFilletNode: PathToNode = [] - - if (extrudeDeclarator.init.type === 'CallExpression') { - // 1. case when no fillet exists - - // modify ast with new fillet call by mutating the extrude node - extrudeDeclarator.init = createPipeExpression([ - extrudeDeclarator.init, - filletCall, - ]) - - // get path to the fillet node - pathToFilletNode = getPathToNodeOfFilletLiteral( - pathToExtrudeNode, - extrudeDeclarator, - tag - ) - - return { modifiedAst: astClone, pathToFilletNode } - } else if (extrudeDeclarator.init.type === 'PipeExpression') { - // 2. case when fillet exists - - const existingFilletCall = extrudeDeclarator.init.body.find((node) => { - return node.type === 'CallExpression' && node.callee.name === 'fillet' - }) - - if (!existingFilletCall || existingFilletCall.type !== 'CallExpression') { - return new Error('Fillet CallExpression not found.') - } - - // check if the existing fillet has the same tag as the new fillet - const filletTag = getFilletTag(existingFilletCall) - - if (filletTag !== tag) { - // mutate the extrude node with the new fillet call - extrudeDeclarator.init.body.push(filletCall) - return { - modifiedAst: astClone, - pathToFilletNode: getPathToNodeOfFilletLiteral( - pathToExtrudeNode, - extrudeDeclarator, - tag - ), - } - } - } else { - return new Error('Unsupported extrude type.') - } - - return { modifiedAst: astClone, pathToFilletNode } -} - function locateExtrudeDeclarator( node: Program, pathToExtrudeNode: PathToNode @@ -439,9 +388,7 @@ function getFilletTag(existingFilletCall: CallExpression): string | null { return null } -/** - * Button states - */ +// Button states export const hasValidFilletSelection = ({ selectionRanges, diff --git a/src/lib/commandBarConfigs/modelingCommandConfig.ts b/src/lib/commandBarConfigs/modelingCommandConfig.ts index 081d708736..43f9c4ccd5 100644 --- a/src/lib/commandBarConfigs/modelingCommandConfig.ts +++ b/src/lib/commandBarConfigs/modelingCommandConfig.ts @@ -258,7 +258,6 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig< }, }, Fillet: { - // todo description: 'Fillet edge', icon: 'fillet', needsReview: true, @@ -269,7 +268,7 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig< 'default', 'line-end', 'line-mid', - 'extrude-wall', // to fix: accepts only this selection type + 'extrude-wall', 'solid2D', 'start-cap', 'end-cap', @@ -279,9 +278,9 @@ export const modelingMachineCommandConfig: StateMachineCommandSetConfig< 'arc', 'all', ], - multiple: true, // TODO: multiple selection like in extrude command + multiple: true, required: true, - skip: true, + skip: false, }, radius: { inputType: 'kcl', From f2e5952b4d85258e386d7e45f0f6d6582110fa3f Mon Sep 17 00:00:00 2001 From: max-mrgrsk <156543465+max-mrgrsk@users.noreply.github.com> Date: Tue, 1 Oct 2024 14:04:59 +0200 Subject: [PATCH 2/6] delete getFilletTag function --- src/lang/modifyAst/addFillet.ts | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/src/lang/modifyAst/addFillet.ts b/src/lang/modifyAst/addFillet.ts index 2efe5381fe..ff58da8d58 100644 --- a/src/lang/modifyAst/addFillet.ts +++ b/src/lang/modifyAst/addFillet.ts @@ -373,21 +373,6 @@ function getPathToRadiusLiteral(node: ObjectExpression, path: any): PathToNode { return pathToFilletObj } -function getFilletTag(existingFilletCall: CallExpression): string | null { - if (existingFilletCall.arguments[0].type === 'ObjectExpression') { - const properties = (existingFilletCall.arguments[0] as ObjectExpression) - .properties - const tagsProperty = properties.find((prop) => prop.key.name === 'tags') - if (tagsProperty && tagsProperty.value.type === 'ArrayExpression') { - const elements = (tagsProperty.value as ArrayExpression).elements - if (elements.length > 0 && elements[0].type === 'Identifier') { - return elements[0].name - } - } - } - return null -} - // Button states export const hasValidFilletSelection = ({ From afef412e156deb025015862e5e91d9ba066f1902 Mon Sep 17 00:00:00 2001 From: max-mrgrsk <156543465+max-mrgrsk@users.noreply.github.com> Date: Wed, 2 Oct 2024 21:43:57 +0200 Subject: [PATCH 3/6] fix playwright test --- e2e/playwright/command-bar-tests.spec.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/e2e/playwright/command-bar-tests.spec.ts b/e2e/playwright/command-bar-tests.spec.ts index 5be7320bf1..e14a40f0e6 100644 --- a/e2e/playwright/command-bar-tests.spec.ts +++ b/e2e/playwright/command-bar-tests.spec.ts @@ -80,9 +80,11 @@ const extrude001 = extrude(-10, sketch001)` await page.waitForTimeout(100) await page.getByRole('button', { name: 'Fillet' }).click() await page.waitForTimeout(100) - await page.keyboard.press('Enter') + await page.keyboard.press('Enter') // skip selection await page.waitForTimeout(100) - await page.keyboard.press('Enter') + await page.keyboard.press('Enter') // accept default radius + await page.waitForTimeout(100) + await page.keyboard.press('Enter') // submit await page.waitForTimeout(100) await expect(page.locator('.cm-activeLine')).toContainText( `fillet({ radius: ${KCL_DEFAULT_LENGTH}, tags: [seg01] }, %)` From 2b3a729550c7f32beb8d298577bb8970f63964f7 Mon Sep 17 00:00:00 2001 From: max-mrgrsk <156543465+max-mrgrsk@users.noreply.github.com> Date: Wed, 2 Oct 2024 21:44:08 +0200 Subject: [PATCH 4/6] make eslint happy --- src/lang/modifyAst/addFillet.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lang/modifyAst/addFillet.ts b/src/lang/modifyAst/addFillet.ts index ff58da8d58..f5bfb56868 100644 --- a/src/lang/modifyAst/addFillet.ts +++ b/src/lang/modifyAst/addFillet.ts @@ -1,5 +1,4 @@ import { - ArrayExpression, CallExpression, ObjectExpression, PathToNode, From e504e68f1fd172ffb99f405c745471dab87dd5bf Mon Sep 17 00:00:00 2001 From: max-mrgrsk <156543465+max-mrgrsk@users.noreply.github.com> Date: Wed, 2 Oct 2024 22:46:18 +0200 Subject: [PATCH 5/6] delete missed 'const' --- src/lang/modifyAst/addFillet.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lang/modifyAst/addFillet.test.ts b/src/lang/modifyAst/addFillet.test.ts index bf3fa3d918..361c32c6f6 100644 --- a/src/lang/modifyAst/addFillet.test.ts +++ b/src/lang/modifyAst/addFillet.test.ts @@ -351,7 +351,7 @@ extrude001 = extrude(-15, sketch001)` |> line([-20, 0], %, $seg02) |> lineTo([profileStartX(%), profileStartY(%)], %) |> close(%) -const extrude001 = extrude(-15, sketch001) +extrude001 = extrude(-15, sketch001) |> fillet({ radius: 3, tags: [seg02] }, %)` await runModifyAstCloneWithFilletAndTag( @@ -369,7 +369,7 @@ const extrude001 = extrude(-15, sketch001) |> line([-20, 0], %) |> lineTo([profileStartX(%), profileStartY(%)], %) |> close(%) -const extrude001 = extrude(-15, sketch001) +extrude001 = extrude(-15, sketch001) |> fillet({ radius: 5, tags: [seg01] }, %)` const segmentSnippets = ['line([-20, 0], %)'] const radiusValue = 3 From bc288f30aa91958cbe33697bab92eb4b48e5863f Mon Sep 17 00:00:00 2001 From: max-mrgrsk <156543465+max-mrgrsk@users.noreply.github.com> Date: Thu, 3 Oct 2024 09:47:20 +0200 Subject: [PATCH 6/6] delete const rev2 --- src/lang/modifyAst/addFillet.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lang/modifyAst/addFillet.test.ts b/src/lang/modifyAst/addFillet.test.ts index 361c32c6f6..cea9928429 100644 --- a/src/lang/modifyAst/addFillet.test.ts +++ b/src/lang/modifyAst/addFillet.test.ts @@ -344,7 +344,7 @@ extrude001 = extrude(-15, sketch001) extrude001 = extrude(-15, sketch001)` const segmentSnippets = ['line([-20, 0], %)'] const radiusValue = 3 - const expectedCode = `const sketch001 = startSketchOn('XY') + const expectedCode = `sketch001 = startSketchOn('XY') |> startProfileAt([-10, 10], %) |> line([20, 0], %, $seg01) |> line([0, -20], %) @@ -362,7 +362,7 @@ extrude001 = extrude(-15, sketch001) ) }) it('should add a fillet with existing fillet on other segment', async () => { - const code = `const sketch001 = startSketchOn('XY') + const code = `sketch001 = startSketchOn('XY') |> startProfileAt([-10, 10], %) |> line([20, 0], %, $seg01) |> line([0, -20], %)