Merge branch 'nadro/gh-5157/center-rectangle-kcl-fix' into achalmers/kw-fn-sketches
This commit is contained in:
@ -34,7 +34,7 @@ test.describe('Sketch tests', () => {
|
|||||||
screwRadius = 3
|
screwRadius = 3
|
||||||
wireRadius = 2
|
wireRadius = 2
|
||||||
wireOffset = 0.5
|
wireOffset = 0.5
|
||||||
|
|
||||||
screwHole = startSketchOn('XY')
|
screwHole = startSketchOn('XY')
|
||||||
${startProfileAt1}
|
${startProfileAt1}
|
||||||
|> arc({
|
|> arc({
|
||||||
@ -42,7 +42,7 @@ test.describe('Sketch tests', () => {
|
|||||||
angleStart = 0,
|
angleStart = 0,
|
||||||
angleEnd = 360
|
angleEnd = 360
|
||||||
}, %)
|
}, %)
|
||||||
|
|
||||||
part001 = startSketchOn('XY')
|
part001 = startSketchOn('XY')
|
||||||
${startProfileAt2}
|
${startProfileAt2}
|
||||||
|> xLine(width * .5, %)
|
|> xLine(width * .5, %)
|
||||||
@ -51,7 +51,7 @@ test.describe('Sketch tests', () => {
|
|||||||
|> close()
|
|> close()
|
||||||
|> hole(screwHole, %)
|
|> hole(screwHole, %)
|
||||||
|> extrude(length = thickness)
|
|> extrude(length = thickness)
|
||||||
|
|
||||||
part002 = startSketchOn('-XZ')
|
part002 = startSketchOn('-XZ')
|
||||||
${startProfileAt3}
|
${startProfileAt3}
|
||||||
|> xLine(width / 4, %)
|
|> xLine(width / 4, %)
|
||||||
@ -99,6 +99,7 @@ test.describe('Sketch tests', () => {
|
|||||||
test('Can delete most of a sketch and the line tool will still work', async ({
|
test('Can delete most of a sketch and the line tool will still work', async ({
|
||||||
page,
|
page,
|
||||||
homePage,
|
homePage,
|
||||||
|
scene,
|
||||||
}) => {
|
}) => {
|
||||||
const u = await getUtils(page)
|
const u = await getUtils(page)
|
||||||
await page.addInitScript(async () => {
|
await page.addInitScript(async () => {
|
||||||
@ -112,12 +113,13 @@ test.describe('Sketch tests', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
await homePage.goToModelingScene()
|
await homePage.goToModelingScene()
|
||||||
|
await scene.waitForExecutionDone()
|
||||||
|
|
||||||
await expect(async () => {
|
await expect(async () => {
|
||||||
await page.getByText('tangentialArcTo([24.95, -5.38], %)').click()
|
await page.getByText('tangentialArcTo([24.95, -5.38], %)').click()
|
||||||
await expect(
|
await expect(
|
||||||
page.getByRole('button', { name: 'Edit Sketch' })
|
page.getByRole('button', { name: 'Edit Sketch' })
|
||||||
).toBeEnabled({ timeout: 1000 })
|
).toBeEnabled({ timeout: 2000 })
|
||||||
await page.getByRole('button', { name: 'Edit Sketch' }).click()
|
await page.getByRole('button', { name: 'Edit Sketch' }).click()
|
||||||
}).toPass({ timeout: 40_000, intervals: [1_000] })
|
}).toPass({ timeout: 40_000, intervals: [1_000] })
|
||||||
|
|
||||||
@ -1066,7 +1068,7 @@ test.describe('Sketch tests', () => {
|
|||||||
`lugHeadLength = 0.25
|
`lugHeadLength = 0.25
|
||||||
lugDiameter = 0.5
|
lugDiameter = 0.5
|
||||||
lugLength = 2
|
lugLength = 2
|
||||||
|
|
||||||
fn lug = (origin, length, diameter, plane) => {
|
fn lug = (origin, length, diameter, plane) => {
|
||||||
lugSketch = startSketchOn(plane)
|
lugSketch = startSketchOn(plane)
|
||||||
|> startProfileAt([origin[0] + lugDiameter / 2, origin[1]], %)
|
|> startProfileAt([origin[0] + lugDiameter / 2, origin[1]], %)
|
||||||
@ -1075,10 +1077,10 @@ test.describe('Sketch tests', () => {
|
|||||||
|> yLineTo(0, %)
|
|> yLineTo(0, %)
|
||||||
|> close()
|
|> close()
|
||||||
|> revolve({ axis = "Y" }, %)
|
|> revolve({ axis = "Y" }, %)
|
||||||
|
|
||||||
return lugSketch
|
return lugSketch
|
||||||
}
|
}
|
||||||
|
|
||||||
lug([0, 0], 10, .5, "XY")`
|
lug([0, 0], 10, .5, "XY")`
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
@ -1130,14 +1132,14 @@ test.describe('Sketch tests', () => {
|
|||||||
`fn in2mm = (inches) => {
|
`fn in2mm = (inches) => {
|
||||||
return inches * 25.4
|
return inches * 25.4
|
||||||
}
|
}
|
||||||
|
|
||||||
const railTop = in2mm(.748)
|
const railTop = in2mm(.748)
|
||||||
const railSide = in2mm(.024)
|
const railSide = in2mm(.024)
|
||||||
const railBaseWidth = in2mm(.612)
|
const railBaseWidth = in2mm(.612)
|
||||||
const railWideWidth = in2mm(.835)
|
const railWideWidth = in2mm(.835)
|
||||||
const railBaseLength = in2mm(.200)
|
const railBaseLength = in2mm(.200)
|
||||||
const railClampable = in2mm(.200)
|
const railClampable = in2mm(.200)
|
||||||
|
|
||||||
const rail = startSketchOn('XZ')
|
const rail = startSketchOn('XZ')
|
||||||
|> startProfileAt([
|
|> startProfileAt([
|
||||||
-railTop / 2,
|
-railTop / 2,
|
||||||
|
@ -5,6 +5,8 @@ import {
|
|||||||
Identifier,
|
Identifier,
|
||||||
SourceRange,
|
SourceRange,
|
||||||
topLevelRange,
|
topLevelRange,
|
||||||
|
LiteralValue,
|
||||||
|
Literal,
|
||||||
} from './wasm'
|
} from './wasm'
|
||||||
import {
|
import {
|
||||||
createLiteral,
|
createLiteral,
|
||||||
@ -37,10 +39,26 @@ beforeAll(async () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
describe('Testing createLiteral', () => {
|
describe('Testing createLiteral', () => {
|
||||||
it('should create a literal', () => {
|
it('should create a literal number without units', () => {
|
||||||
const result = createLiteral(5)
|
const result = createLiteral(5)
|
||||||
expect(result.type).toBe('Literal')
|
expect(result.type).toBe('Literal')
|
||||||
expect((result as any).value.value).toBe(5)
|
expect((result as any).value.value).toBe(5)
|
||||||
|
expect((result as any).value.suffix).toBe('None')
|
||||||
|
expect((result as Literal).raw).toBe('5')
|
||||||
|
})
|
||||||
|
it('should create a literal number with units', () => {
|
||||||
|
const lit: LiteralValue = { value: 5, suffix: 'Mm' }
|
||||||
|
const result = createLiteral(lit)
|
||||||
|
expect(result.type).toBe('Literal')
|
||||||
|
expect((result as any).value.value).toBe(5)
|
||||||
|
expect((result as any).value.suffix).toBe('Mm')
|
||||||
|
expect((result as Literal).raw).toBe('5mm')
|
||||||
|
})
|
||||||
|
it('should create a literal boolean', () => {
|
||||||
|
const result = createLiteral(false)
|
||||||
|
expect(result.type).toBe('Literal')
|
||||||
|
expect((result as Literal).value).toBe(false)
|
||||||
|
expect((result as Literal).raw).toBe('false')
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
describe('Testing createIdentifier', () => {
|
describe('Testing createIdentifier', () => {
|
||||||
|
@ -22,6 +22,7 @@ import {
|
|||||||
SourceRange,
|
SourceRange,
|
||||||
sketchFromKclValue,
|
sketchFromKclValue,
|
||||||
isPathToNodeNumber,
|
isPathToNodeNumber,
|
||||||
|
formatNumber,
|
||||||
} from './wasm'
|
} from './wasm'
|
||||||
import {
|
import {
|
||||||
isNodeSafeToReplacePath,
|
isNodeSafeToReplacePath,
|
||||||
@ -780,11 +781,26 @@ export function splitPathAtPipeExpression(pathToNode: PathToNode): {
|
|||||||
return splitPathAtPipeExpression(pathToNode.slice(0, -1))
|
return splitPathAtPipeExpression(pathToNode.slice(0, -1))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note: This depends on WASM, but it's not async. Callers are responsible for
|
||||||
|
* awaiting init of the WASM module.
|
||||||
|
*/
|
||||||
export function createLiteral(value: LiteralValue | number): Node<Literal> {
|
export function createLiteral(value: LiteralValue | number): Node<Literal> {
|
||||||
const raw = `${value}`
|
|
||||||
if (typeof value === 'number') {
|
if (typeof value === 'number') {
|
||||||
value = { value, suffix: 'None' }
|
value = { value, suffix: 'None' }
|
||||||
}
|
}
|
||||||
|
let raw: string
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
// TODO: Should we handle escape sequences?
|
||||||
|
raw = `${value}`
|
||||||
|
} else if (typeof value === 'boolean') {
|
||||||
|
raw = `${value}`
|
||||||
|
} else if (typeof value.value === 'number' && value.suffix === 'None') {
|
||||||
|
// Fast path for numbers when there are no units.
|
||||||
|
raw = `${value.value}`
|
||||||
|
} else {
|
||||||
|
raw = formatNumber(value.value, value.suffix)
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
type: 'Literal',
|
type: 'Literal',
|
||||||
start: 0,
|
start: 0,
|
||||||
|
@ -8,6 +8,8 @@ import {
|
|||||||
ArtifactGraph,
|
ArtifactGraph,
|
||||||
CallExpressionKw,
|
CallExpressionKw,
|
||||||
Expr,
|
Expr,
|
||||||
|
LiteralValue,
|
||||||
|
NumericSuffix,
|
||||||
} from './wasm'
|
} from './wasm'
|
||||||
import { filterArtifacts } from 'lang/std/artifactGraph'
|
import { filterArtifacts } from 'lang/std/artifactGraph'
|
||||||
import { isOverlap } from 'lib/utils'
|
import { isOverlap } from 'lib/utils'
|
||||||
@ -111,3 +113,15 @@ export function findKwArgAnyIndex(
|
|||||||
export function isAbsolute(call: CallExpressionKw): boolean {
|
export function isAbsolute(call: CallExpressionKw): boolean {
|
||||||
return findKwArgAny(['endAbsolute'], call) !== undefined
|
return findKwArgAny(['endAbsolute'], call) !== undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isLiteralValueNumber(
|
||||||
|
e: LiteralValue
|
||||||
|
): e is { value: number; suffix: NumericSuffix } {
|
||||||
|
return (
|
||||||
|
typeof e === 'object' &&
|
||||||
|
'value' in e &&
|
||||||
|
typeof e.value === 'number' &&
|
||||||
|
'suffix' in e &&
|
||||||
|
typeof e.suffix === 'string'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { err } from 'lib/trap'
|
import { err } from 'lib/trap'
|
||||||
import { initPromise, parse, ParseResult } from './wasm'
|
import { formatNumber, initPromise, parse, ParseResult } from './wasm'
|
||||||
import { enginelessExecutor } from 'lib/testHelpers'
|
import { enginelessExecutor } from 'lib/testHelpers'
|
||||||
import { Node } from 'wasm-lib/kcl/bindings/Node'
|
import { Node } from 'wasm-lib/kcl/bindings/Node'
|
||||||
import { Program } from '../wasm-lib/kcl/bindings/Program'
|
import { Program } from '../wasm-lib/kcl/bindings/Program'
|
||||||
@ -20,3 +20,12 @@ it('can execute parsed AST', async () => {
|
|||||||
expect(err(execState)).toEqual(false)
|
expect(err(execState)).toEqual(false)
|
||||||
expect(execState.memory.get('x')?.value).toEqual(1)
|
expect(execState.memory.get('x')?.value).toEqual(1)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('formats numbers with units', () => {
|
||||||
|
expect(formatNumber(1, 'None')).toEqual('1')
|
||||||
|
expect(formatNumber(1, 'Count')).toEqual('1_')
|
||||||
|
expect(formatNumber(1, 'Mm')).toEqual('1mm')
|
||||||
|
expect(formatNumber(1, 'Inch')).toEqual('1in')
|
||||||
|
expect(formatNumber(0.5, 'Mm')).toEqual('0.5mm')
|
||||||
|
expect(formatNumber(-0.5, 'Mm')).toEqual('-0.5mm')
|
||||||
|
})
|
||||||
|
@ -2,6 +2,7 @@ import {
|
|||||||
init,
|
init,
|
||||||
parse_wasm,
|
parse_wasm,
|
||||||
recast_wasm,
|
recast_wasm,
|
||||||
|
format_number,
|
||||||
execute,
|
execute,
|
||||||
kcl_lint,
|
kcl_lint,
|
||||||
modify_ast_for_sketch_wasm,
|
modify_ast_for_sketch_wasm,
|
||||||
@ -54,6 +55,7 @@ import { ArtifactCommand } from 'wasm-lib/kcl/bindings/Artifact'
|
|||||||
import { ArtifactGraph as RustArtifactGraph } from 'wasm-lib/kcl/bindings/Artifact'
|
import { ArtifactGraph as RustArtifactGraph } from 'wasm-lib/kcl/bindings/Artifact'
|
||||||
import { Artifact } from './std/artifactGraph'
|
import { Artifact } from './std/artifactGraph'
|
||||||
import { getNodePathFromSourceRange } from 'lang/queryAstNodePathUtils'
|
import { getNodePathFromSourceRange } from 'lang/queryAstNodePathUtils'
|
||||||
|
import { NumericSuffix } from 'wasm-lib/kcl/bindings/NumericSuffix'
|
||||||
|
|
||||||
export type { Artifact } from 'wasm-lib/kcl/bindings/Artifact'
|
export type { Artifact } from 'wasm-lib/kcl/bindings/Artifact'
|
||||||
export type { ArtifactCommand } from 'wasm-lib/kcl/bindings/Artifact'
|
export type { ArtifactCommand } from 'wasm-lib/kcl/bindings/Artifact'
|
||||||
@ -92,6 +94,7 @@ export type { Literal } from '../wasm-lib/kcl/bindings/Literal'
|
|||||||
export type { LiteralValue } from '../wasm-lib/kcl/bindings/LiteralValue'
|
export type { LiteralValue } from '../wasm-lib/kcl/bindings/LiteralValue'
|
||||||
export type { ArrayExpression } from '../wasm-lib/kcl/bindings/ArrayExpression'
|
export type { ArrayExpression } from '../wasm-lib/kcl/bindings/ArrayExpression'
|
||||||
export type { SourceRange } from 'wasm-lib/kcl/bindings/SourceRange'
|
export type { SourceRange } from 'wasm-lib/kcl/bindings/SourceRange'
|
||||||
|
export type { NumericSuffix } from 'wasm-lib/kcl/bindings/NumericSuffix'
|
||||||
|
|
||||||
export type SyntaxType =
|
export type SyntaxType =
|
||||||
| 'Program'
|
| 'Program'
|
||||||
@ -642,6 +645,13 @@ export const recast = (ast: Program): string | Error => {
|
|||||||
return recast_wasm(JSON.stringify(ast))
|
return recast_wasm(JSON.stringify(ast))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format a number with suffix as KCL.
|
||||||
|
*/
|
||||||
|
export function formatNumber(value: number, suffix: NumericSuffix): string {
|
||||||
|
return format_number(value, JSON.stringify(suffix))
|
||||||
|
}
|
||||||
|
|
||||||
export const makeDefaultPlanes = async (
|
export const makeDefaultPlanes = async (
|
||||||
engineCommandManager: EngineCommandManager
|
engineCommandManager: EngineCommandManager
|
||||||
): Promise<DefaultPlanes> => {
|
): Promise<DefaultPlanes> => {
|
||||||
|
92
src/lib/rectangleTool.test.ts
Normal file
92
src/lib/rectangleTool.test.ts
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
import { expect } from 'vitest'
|
||||||
|
import {
|
||||||
|
recast,
|
||||||
|
assertParse,
|
||||||
|
topLevelRange,
|
||||||
|
VariableDeclaration,
|
||||||
|
initPromise,
|
||||||
|
} from 'lang/wasm'
|
||||||
|
import { updateCenterRectangleSketch } from './rectangleTool'
|
||||||
|
import { getNodePathFromSourceRange } from 'lang/queryAstNodePathUtils'
|
||||||
|
import { getNodeFromPath } from 'lang/queryAst'
|
||||||
|
import { findUniqueName } from 'lang/modifyAst'
|
||||||
|
import { err, trap } from './trap'
|
||||||
|
|
||||||
|
beforeAll(async () => {
|
||||||
|
await initPromise
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('library rectangleTool helper functions', () => {
|
||||||
|
describe('updateCenterRectangleSketch', () => {
|
||||||
|
// regression test for https://github.com/KittyCAD/modeling-app/issues/5157
|
||||||
|
test('should update AST and source code', async () => {
|
||||||
|
// Base source code that will be edited in place
|
||||||
|
const sourceCode = `sketch001 = startSketchOn('XZ')
|
||||||
|
|> startProfileAt([120.37, 162.76], %)
|
||||||
|
|> angledLine([0, 0], %, $rectangleSegmentA001)
|
||||||
|
|> angledLine([segAng(rectangleSegmentA001) + 90, 0], %, $rectangleSegmentB001)
|
||||||
|
|> angledLine([
|
||||||
|
segAng(rectangleSegmentA001),
|
||||||
|
-segLen(rectangleSegmentA001)
|
||||||
|
], %, $rectangleSegmentC001)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
`
|
||||||
|
// Create ast
|
||||||
|
const _ast = assertParse(sourceCode)
|
||||||
|
let ast = structuredClone(_ast)
|
||||||
|
|
||||||
|
// Find some nodes and paths to reference
|
||||||
|
const sketchSnippet = `startProfileAt([120.37, 162.76], %)`
|
||||||
|
const sketchRange = topLevelRange(
|
||||||
|
sourceCode.indexOf(sketchSnippet),
|
||||||
|
sourceCode.indexOf(sketchSnippet) + sketchSnippet.length
|
||||||
|
)
|
||||||
|
const sketchPathToNode = getNodePathFromSourceRange(ast, sketchRange)
|
||||||
|
const _node = getNodeFromPath<VariableDeclaration>(
|
||||||
|
ast,
|
||||||
|
sketchPathToNode || [],
|
||||||
|
'VariableDeclaration'
|
||||||
|
)
|
||||||
|
if (trap(_node)) return
|
||||||
|
const sketchInit = _node.node?.declaration.init
|
||||||
|
|
||||||
|
// Hard code inputs that a user would have taken with their mouse
|
||||||
|
const x = 40
|
||||||
|
const y = 60
|
||||||
|
const rectangleOrigin = [120, 180]
|
||||||
|
const tags: [string, string, string] = [
|
||||||
|
'rectangleSegmentA001',
|
||||||
|
'rectangleSegmentB001',
|
||||||
|
'rectangleSegmentC001',
|
||||||
|
]
|
||||||
|
|
||||||
|
// Update the ast
|
||||||
|
if (sketchInit.type === 'PipeExpression') {
|
||||||
|
updateCenterRectangleSketch(
|
||||||
|
sketchInit,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
tags[0],
|
||||||
|
rectangleOrigin[0],
|
||||||
|
rectangleOrigin[1]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ast is edited in place from the updateCenterRectangleSketch
|
||||||
|
const expectedSourceCode = `sketch001 = startSketchOn('XZ')
|
||||||
|
|> startProfileAt([80, 120], %)
|
||||||
|
|> angledLine([0, 80], %, $rectangleSegmentA001)
|
||||||
|
|> angledLine([segAng(rectangleSegmentA001) + 90, 120], %, $rectangleSegmentB001)
|
||||||
|
|> angledLine([
|
||||||
|
segAng(rectangleSegmentA001),
|
||||||
|
-segLen(rectangleSegmentA001)
|
||||||
|
], %, $rectangleSegmentC001)
|
||||||
|
|> lineTo([profileStartX(%), profileStartY(%)], %)
|
||||||
|
|> close(%)
|
||||||
|
`
|
||||||
|
const recasted = recast(ast)
|
||||||
|
expect(recasted).toEqual(expectedSourceCode)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
@ -10,13 +10,19 @@ import {
|
|||||||
createTagDeclarator,
|
createTagDeclarator,
|
||||||
createUnaryExpression,
|
createUnaryExpression,
|
||||||
} from 'lang/modifyAst'
|
} from 'lang/modifyAst'
|
||||||
import { ArrayExpression, CallExpression, PipeExpression } from 'lang/wasm'
|
import {
|
||||||
|
ArrayExpression,
|
||||||
|
CallExpression,
|
||||||
|
PipeExpression,
|
||||||
|
recast,
|
||||||
|
} from 'lang/wasm'
|
||||||
import { roundOff } from 'lib/utils'
|
import { roundOff } from 'lib/utils'
|
||||||
import {
|
import {
|
||||||
isCallExpression,
|
isCallExpression,
|
||||||
isArrayExpression,
|
isArrayExpression,
|
||||||
isLiteral,
|
isLiteral,
|
||||||
isBinaryExpression,
|
isBinaryExpression,
|
||||||
|
isLiteralValueNumber,
|
||||||
} from 'lang/util'
|
} from 'lang/util'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -144,10 +150,12 @@ export function updateCenterRectangleSketch(
|
|||||||
if (isArrayExpression(arrayExpression)) {
|
if (isArrayExpression(arrayExpression)) {
|
||||||
const literal = arrayExpression.elements[0]
|
const literal = arrayExpression.elements[0]
|
||||||
if (isLiteral(literal)) {
|
if (isLiteral(literal)) {
|
||||||
callExpression.arguments[0] = createArrayExpression([
|
if (isLiteralValueNumber(literal.value)) {
|
||||||
createLiteral(literal.value),
|
callExpression.arguments[0] = createArrayExpression([
|
||||||
createLiteral(Math.abs(twoX)),
|
createLiteral(literal.value),
|
||||||
])
|
createLiteral(Math.abs(twoX)),
|
||||||
|
])
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
import {
|
import {
|
||||||
parse_wasm as ParseWasm,
|
parse_wasm as ParseWasm,
|
||||||
recast_wasm as RecastWasm,
|
recast_wasm as RecastWasm,
|
||||||
|
format_number as FormatNumber,
|
||||||
execute as Execute,
|
execute as Execute,
|
||||||
kcl_lint as KclLint,
|
kcl_lint as KclLint,
|
||||||
modify_ast_for_sketch_wasm as ModifyAstForSketch,
|
modify_ast_for_sketch_wasm as ModifyAstForSketch,
|
||||||
@ -51,6 +52,9 @@ export const parse_wasm: typeof ParseWasm = (...args) => {
|
|||||||
export const recast_wasm: typeof RecastWasm = (...args) => {
|
export const recast_wasm: typeof RecastWasm = (...args) => {
|
||||||
return getModule().recast_wasm(...args)
|
return getModule().recast_wasm(...args)
|
||||||
}
|
}
|
||||||
|
export const format_number: typeof FormatNumber = (...args) => {
|
||||||
|
return getModule().format_number(...args)
|
||||||
|
}
|
||||||
export const execute: typeof Execute = (...args) => {
|
export const execute: typeof Execute = (...args) => {
|
||||||
return getModule().execute(...args)
|
return getModule().execute(...args)
|
||||||
}
|
}
|
||||||
|
@ -120,6 +120,11 @@ pub mod std_utils {
|
|||||||
pub use crate::std::utils::{get_tangential_arc_to_info, is_points_ccw_wasm, TangentialArcInfoInput};
|
pub use crate::std::utils::{get_tangential_arc_to_info, is_points_ccw_wasm, TangentialArcInfoInput};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod pretty {
|
||||||
|
pub use crate::parsing::token::NumericSuffix;
|
||||||
|
pub use crate::unparser::format_number;
|
||||||
|
}
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
|
@ -8,6 +8,7 @@ use crate::parsing::{
|
|||||||
LiteralValue, MemberExpression, MemberObject, Node, NonCodeNode, NonCodeValue, ObjectExpression, Parameter,
|
LiteralValue, MemberExpression, MemberObject, Node, NonCodeNode, NonCodeValue, ObjectExpression, Parameter,
|
||||||
PipeExpression, Program, TagDeclarator, UnaryExpression, VariableDeclaration, VariableKind,
|
PipeExpression, Program, TagDeclarator, UnaryExpression, VariableDeclaration, VariableKind,
|
||||||
},
|
},
|
||||||
|
token::NumericSuffix,
|
||||||
PIPE_OPERATOR,
|
PIPE_OPERATOR,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -370,6 +371,11 @@ impl VariableDeclaration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Used by TS.
|
||||||
|
pub fn format_number(value: f64, suffix: NumericSuffix) -> String {
|
||||||
|
format!("{value}{suffix}")
|
||||||
|
}
|
||||||
|
|
||||||
impl Literal {
|
impl Literal {
|
||||||
fn recast(&self) -> String {
|
fn recast(&self) -> String {
|
||||||
match self.value {
|
match self.value {
|
||||||
|
@ -5,7 +5,8 @@ use std::sync::Arc;
|
|||||||
use futures::stream::TryStreamExt;
|
use futures::stream::TryStreamExt;
|
||||||
use gloo_utils::format::JsValueSerdeExt;
|
use gloo_utils::format::JsValueSerdeExt;
|
||||||
use kcl_lib::{
|
use kcl_lib::{
|
||||||
exec::IdGenerator, CacheInformation, CoreDump, EngineManager, ExecState, ModuleId, OldAstState, Point2d, Program,
|
exec::IdGenerator, pretty::NumericSuffix, CacheInformation, CoreDump, EngineManager, ExecState, ModuleId,
|
||||||
|
OldAstState, Point2d, Program,
|
||||||
};
|
};
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
use tower_lsp::{LspService, Server};
|
use tower_lsp::{LspService, Server};
|
||||||
@ -251,6 +252,14 @@ pub fn recast_wasm(json_str: &str) -> Result<JsValue, JsError> {
|
|||||||
Ok(JsValue::from_serde(&program.recast())?)
|
Ok(JsValue::from_serde(&program.recast())?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub fn format_number(value: f64, suffix_json: &str) -> Result<String, JsError> {
|
||||||
|
console_error_panic_hook::set_once();
|
||||||
|
|
||||||
|
let suffix: NumericSuffix = serde_json::from_str(suffix_json).map_err(JsError::from)?;
|
||||||
|
Ok(kcl_lib::pretty::format_number(value, suffix))
|
||||||
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub struct ServerConfig {
|
pub struct ServerConfig {
|
||||||
into_server: js_sys::AsyncIterator,
|
into_server: js_sys::AsyncIterator,
|
||||||
|
Reference in New Issue
Block a user