Compare commits

...

11 Commits

Author SHA1 Message Date
4a5ef17c92 Remove extra console error that shouldn't be needed anymore 2025-04-18 17:23:54 -04:00
83220a7255 Add text to the error message when JSON parse fails 2025-04-18 17:19:50 -04:00
a0f3f0f50e Fix KCLError to have a real message (#6396)
* Fix KCLError to have a real message

* Remove unneeded error exception
2025-04-18 17:13:09 -04:00
dad0d5488f Support any installation path for rust toolchain (#6380) 2025-04-18 20:28:38 +00:00
77773fb052 ci: Add error to console exception (#6392)
* Add error to console exception

* Ignore in codespell

* Increase retry on snapshots

* Fixme's all around

---------

Co-authored-by: Jace Browning <jacebrowning@gmail.com>
Co-authored-by: Frank Noirot <frankjohnson1993@gmail.com>
2025-04-18 15:51:13 -04:00
1240ca6f21 Revert "Update onboarding interactive numbers test to use editor fixture" (#6393)
Revert "Update onboarding interactive numbers test to use editor fixture (#6356)"

This reverts commit c77bb92da9.
2025-04-18 14:57:40 -04:00
ce3a6ad286 Revert "Remove all use of bold mono font" (#6394)
Revert "Remove all use of bold mono font (#6373)"

This reverts commit 03c4121ab7.
2025-04-18 14:57:10 -04:00
a20f420a55 Add fixmes to failing e2e tests (#6388)
* Add fixmes to bad snapshots tests

* max attempts to 5 on snapshots

* Skip revolve on windows

* Another one

* Add fixme to edit with ML snapshot test

* fmt

* Use absolute import, fix lint

* Disable another test

---------

Co-authored-by: Frank Noirot <frankjohnson1993@gmail.com>
2025-04-18 14:14:23 -04:00
03c4121ab7 Remove all use of bold mono font (#6373)
* Remove all use of bold mono font
A few mono font points are left, mostly for numbers which look better in
monospace.

* make React happy with `clipRule`
2025-04-18 14:11:20 -04:00
8c2c877817 Bump crossbeam-channel from 0.5.14 to 0.5.15 in /rust in the security group (#6354)
Bump crossbeam-channel in /rust in the security group

Bumps the security group in /rust with 1 update: [crossbeam-channel](https://github.com/crossbeam-rs/crossbeam).


Updates `crossbeam-channel` from 0.5.14 to 0.5.15
- [Release notes](https://github.com/crossbeam-rs/crossbeam/releases)
- [Changelog](https://github.com/crossbeam-rs/crossbeam/blob/master/CHANGELOG.md)
- [Commits](https://github.com/crossbeam-rs/crossbeam/compare/crossbeam-channel-0.5.14...crossbeam-channel-0.5.15)

---
updated-dependencies:
- dependency-name: crossbeam-channel
  dependency-version: 0.5.15
  dependency-type: indirect
  dependency-group: security
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-18 14:10:54 -04:00
c77bb92da9 Update onboarding interactive numbers test to use editor fixture (#6356)
Trying to bring it down from the leaderboard of failed tests.

Co-authored-by: Pierre Jacquier <pierrejacquier39@gmail.com>
2025-04-18 14:06:23 -04:00
15 changed files with 65 additions and 37 deletions

View File

@ -1,3 +1,3 @@
[codespell] [codespell]
ignore-words-list: crate,everytime,inout,co-ordinate,ot,nwo,atleast,ue,afterall,ser,fromM,FromM ignore-words-list: crate,everytime,inout,co-ordinate,ot,nwo,atleast,ue,afterall,ser,fromM,FromM
skip: **/target,node_modules,build,dist,./out,**/Cargo.lock,./docs/kcl/*.md,.package-lock.json,**/package-lock.json,./openapi/*.json,./packages/codemirror-lang-kcl/test/all.test.ts,./public/kcl-samples,./rust/kcl-lib/tests/kcl_samples,tsconfig.tsbuildinfo,./src/lib/machine-api.d.ts skip: **/target,node_modules,build,dist,./out,**/Cargo.lock,./docs/kcl/*.md,./e2e/playwright/lib/console-error-whitelist.ts,.package-lock.json,**/package-lock.json,./openapi/*.json,./packages/codemirror-lang-kcl/test/all.test.ts,./public/kcl-samples,./rust/kcl-lib/tests/kcl_samples,tsconfig.tsbuildinfo,./src/lib/machine-api.d.ts

View File

@ -226,8 +226,8 @@ jobs:
with: with:
shell: bash shell: bash
command: npm run test:snapshots command: npm run test:snapshots
timeout_minutes: 30 timeout_minutes: 5
max_attempts: 3 max_attempts: 5
env: env:
token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }} token: ${{ secrets.KITTYCAD_API_TOKEN_DEV }}
snapshottoken: ${{ secrets.KITTYCAD_API_TOKEN }} snapshottoken: ${{ secrets.KITTYCAD_API_TOKEN }}

View File

@ -15,8 +15,8 @@ ifdef WINDOWS
CARGO ?= $(USERPROFILE)/.cargo/bin/cargo.exe CARGO ?= $(USERPROFILE)/.cargo/bin/cargo.exe
WASM_PACK ?= $(USERPROFILE)/.cargo/bin/wasm-pack.exe WASM_PACK ?= $(USERPROFILE)/.cargo/bin/wasm-pack.exe
else else
CARGO ?= ~/.cargo/bin/cargo CARGO ?= $(shell which cargo || echo ~/.cargo/bin/cargo)
WASM_PACK ?= ~/.cargo/bin/wasm-pack WASM_PACK ?= $(shell which wasm-pack || echo ~/.cargo/bin/wasm-pack)
endif endif
.PHONY: install .PHONY: install

View File

@ -5,7 +5,10 @@ import type { Locator, Page } from '@playwright/test'
import type { EditorFixture } from '@e2e/playwright/fixtures/editorFixture' import type { EditorFixture } from '@e2e/playwright/fixtures/editorFixture'
import type { SceneFixture } from '@e2e/playwright/fixtures/sceneFixture' import type { SceneFixture } from '@e2e/playwright/fixtures/sceneFixture'
import type { ToolbarFixture } from '@e2e/playwright/fixtures/toolbarFixture' import type { ToolbarFixture } from '@e2e/playwright/fixtures/toolbarFixture'
import { orRunWhenFullSuiteEnabled } from '@e2e/playwright/test-utils' import {
orRunWhenFullSuiteEnabled,
runningOnWindows,
} from '@e2e/playwright/test-utils'
import { expect, test } from '@e2e/playwright/zoo-test' import { expect, test } from '@e2e/playwright/zoo-test'
// test file is for testing point an click code gen functionality that's not sketch mode related // test file is for testing point an click code gen functionality that's not sketch mode related
@ -3544,6 +3547,9 @@ tag=$rectangleSegmentC002,
toolbar, toolbar,
cmdBar, cmdBar,
}) => { }) => {
if (runningOnWindows()) {
test.fixme(orRunWhenFullSuiteEnabled())
}
const initialCode = `sketch001 = startSketchOn(XZ) const initialCode = `sketch001 = startSketchOn(XZ)
|> startProfileAt([-102.57, 101.72], %) |> startProfileAt([-102.57, 101.72], %)
|> angledLine(angle = 0, length = 202.6, tag = $rectangleSegmentA001) |> angledLine(angle = 0, length = 202.6, tag = $rectangleSegmentA001)

View File

@ -1,4 +1,5 @@
import { expect, test } from '@e2e/playwright/zoo-test' import { expect, test } from '@e2e/playwright/zoo-test'
import { orRunWhenFullSuiteEnabled } from '@e2e/playwright/test-utils'
/* eslint-disable jest/no-conditional-expect */ /* eslint-disable jest/no-conditional-expect */
@ -57,6 +58,7 @@ test.describe('edit with AI example snapshots', () => {
`change colour`, `change colour`,
{ tag: '@snapshot' }, { tag: '@snapshot' },
async ({ context, homePage, cmdBar, editor, page, scene }) => { async ({ context, homePage, cmdBar, editor, page, scene }) => {
test.fixme(orRunWhenFullSuiteEnabled())
await context.addInitScript((file) => { await context.addInitScript((file) => {
localStorage.setItem('persistCode', file) localStorage.setItem('persistCode', file)
}, file) }, file)

View File

@ -377,8 +377,7 @@ test.describe(
'extrude on default planes should be stable', 'extrude on default planes should be stable',
{ tag: '@snapshot' }, { tag: '@snapshot' },
() => { () => {
// FIXME: Skip on macos its being weird. test.fixme(orRunWhenFullSuiteEnabled())
test.skip(process.platform === 'darwin', 'Skip on macos')
test('XY', async ({ page, context, cmdBar, scene }) => { test('XY', async ({ page, context, cmdBar, scene }) => {
await extrudeDefaultPlane(context, page, cmdBar, scene, 'XY') await extrudeDefaultPlane(context, page, cmdBar, scene, 'XY')
@ -410,6 +409,7 @@ test(
'Draft segments should look right', 'Draft segments should look right',
{ tag: '@snapshot' }, { tag: '@snapshot' },
async ({ page, scene, toolbar }) => { async ({ page, scene, toolbar }) => {
test.fixme(orRunWhenFullSuiteEnabled())
const u = await getUtils(page) const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 }) await page.setViewportSize({ width: 1200, height: 500 })
const PUR = 400 / 37.5 //pixeltoUnitRatio const PUR = 400 / 37.5 //pixeltoUnitRatio
@ -534,8 +534,7 @@ test(
'Draft rectangles should look right', 'Draft rectangles should look right',
{ tag: '@snapshot' }, { tag: '@snapshot' },
async ({ page, context, cmdBar, scene }) => { async ({ page, context, cmdBar, scene }) => {
// FIXME: Skip on macos its being weird. test.fixme(orRunWhenFullSuiteEnabled())
test.skip(process.platform === 'darwin', 'Skip on macos')
const u = await getUtils(page) const u = await getUtils(page)
await page.setViewportSize({ width: 1200, height: 500 }) await page.setViewportSize({ width: 1200, height: 500 })
@ -629,8 +628,7 @@ test.describe(
'Client side scene scale should match engine scale', 'Client side scene scale should match engine scale',
{ tag: '@snapshot' }, { tag: '@snapshot' },
() => { () => {
// FIXME: Skip on macos its being weird. test.fixme(orRunWhenFullSuiteEnabled())
test.skip(process.platform === 'darwin', 'Skip on macos')
test('Inch scale', async ({ page, cmdBar, scene }) => { test('Inch scale', async ({ page, cmdBar, scene }) => {
const u = await getUtils(page) const u = await getUtils(page)
@ -807,8 +805,7 @@ test(
'Sketch on face with none z-up', 'Sketch on face with none z-up',
{ tag: '@snapshot' }, { tag: '@snapshot' },
async ({ page, context, cmdBar, scene }) => { async ({ page, context, cmdBar, scene }) => {
// FIXME: Skip on macos its being weird. test.fixme(orRunWhenFullSuiteEnabled())
test.skip(process.platform === 'darwin', 'Skip on macos')
const u = await getUtils(page) const u = await getUtils(page)
await context.addInitScript(async (KCL_DEFAULT_LENGTH) => { await context.addInitScript(async (KCL_DEFAULT_LENGTH) => {
@ -868,8 +865,7 @@ test(
'Zoom to fit on load - solid 2d', 'Zoom to fit on load - solid 2d',
{ tag: '@snapshot' }, { tag: '@snapshot' },
async ({ page, context, cmdBar, scene }) => { async ({ page, context, cmdBar, scene }) => {
// FIXME: Skip on macos its being weird. test.fixme(orRunWhenFullSuiteEnabled())
test.skip(process.platform === 'darwin', 'Skip on macos')
const u = await getUtils(page) const u = await getUtils(page)
await context.addInitScript(async () => { await context.addInitScript(async () => {
@ -907,8 +903,7 @@ test(
'Zoom to fit on load - solid 3d', 'Zoom to fit on load - solid 3d',
{ tag: '@snapshot' }, { tag: '@snapshot' },
async ({ page, context, cmdBar, scene }) => { async ({ page, context, cmdBar, scene }) => {
// FIXME: Skip on macos its being weird. test.fixme(orRunWhenFullSuiteEnabled())
test.skip(process.platform === 'darwin', 'Skip on macos')
const u = await getUtils(page) const u = await getUtils(page)
await context.addInitScript(async () => { await context.addInitScript(async () => {
@ -949,6 +944,7 @@ test.describe('Grid visibility', { tag: '@snapshot' }, () => {
cmdBar, cmdBar,
scene, scene,
}) => { }) => {
test.fixme(orRunWhenFullSuiteEnabled())
const u = await getUtils(page) const u = await getUtils(page)
const stream = page.getByTestId('stream') const stream = page.getByTestId('stream')
@ -1008,6 +1004,7 @@ test.describe('Grid visibility', { tag: '@snapshot' }, () => {
}) })
test('Grid turned off', async ({ page, cmdBar, scene }) => { test('Grid turned off', async ({ page, cmdBar, scene }) => {
test.fixme(orRunWhenFullSuiteEnabled())
const u = await getUtils(page) const u = await getUtils(page)
const stream = page.getByTestId('stream') const stream = page.getByTestId('stream')
@ -1029,6 +1026,7 @@ test.describe('Grid visibility', { tag: '@snapshot' }, () => {
}) })
test('Grid turned on', async ({ page, context, cmdBar, scene }) => { test('Grid turned on', async ({ page, context, cmdBar, scene }) => {
test.fixme(orRunWhenFullSuiteEnabled())
await context.addInitScript( await context.addInitScript(
async ({ settingsKey, settings }) => { async ({ settingsKey, settings }) => {
localStorage.setItem(settingsKey, settings) localStorage.setItem(settingsKey, settings)
@ -1138,6 +1136,7 @@ test('theme persists', async ({ page, context }) => {
test.describe('code color goober', { tag: '@snapshot' }, () => { test.describe('code color goober', { tag: '@snapshot' }, () => {
test('code color goober', async ({ page, context, scene, cmdBar }) => { test('code color goober', async ({ page, context, scene, cmdBar }) => {
test.fixme(orRunWhenFullSuiteEnabled())
const u = await getUtils(page) const u = await getUtils(page)
await context.addInitScript(async () => { await context.addInitScript(async () => {
localStorage.setItem( localStorage.setItem(

4
rust/Cargo.lock generated
View File

@ -665,9 +665,9 @@ dependencies = [
[[package]] [[package]]
name = "crossbeam-channel" name = "crossbeam-channel"
version = "0.5.14" version = "0.5.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2"
dependencies = [ dependencies = [
"crossbeam-utils", "crossbeam-utils",
] ]

View File

@ -3,6 +3,7 @@ import { useEffect, useState } from 'react'
import type { CommandLog } from '@src/lang/std/commandLog' import type { CommandLog } from '@src/lang/std/commandLog'
import { engineCommandManager } from '@src/lib/singletons' import { engineCommandManager } from '@src/lib/singletons'
import { reportRejection } from '@src/lib/trap' import { reportRejection } from '@src/lib/trap'
import { parseJson } from '@src/lib/utils'
export function useEngineCommands(): [CommandLog[], () => void] { export function useEngineCommands(): [CommandLog[], () => void] {
const [engineCommands, setEngineCommands] = useState<CommandLog[]>( const [engineCommands, setEngineCommands] = useState<CommandLog[]>(
@ -84,7 +85,7 @@ export const EngineCommands = () => {
data-testid="custom-cmd-send-button" data-testid="custom-cmd-send-button"
onClick={() => { onClick={() => {
engineCommandManager engineCommandManager
.sendSceneCommand(JSON.parse(customCmd)) .sendSceneCommand(parseJson(customCmd))
.catch(reportRejection) .catch(reportRejection)
}} }}
> >

View File

@ -37,7 +37,7 @@ export class KCLError extends Error {
filenames: { [x: number]: ModulePath | undefined }, filenames: { [x: number]: ModulePath | undefined },
defaultPlanes: DefaultPlanes | null defaultPlanes: DefaultPlanes | null
) { ) {
super() super(`${kind}: ${msg}`)
this.kind = kind this.kind = kind
this.msg = msg this.msg = msg
this.sourceRange = sourceRange this.sourceRange = sourceRange

View File

@ -4,6 +4,7 @@ import path from 'node:path'
import { assertParse } from '@src/lang/wasm' import { assertParse } from '@src/lang/wasm'
import { initPromise } from '@src/lang/wasmUtils' import { initPromise } from '@src/lang/wasmUtils'
import { enginelessExecutor } from '@src/lib/testHelpers' import { enginelessExecutor } from '@src/lib/testHelpers'
import { parseJson } from '@src/lib/utils'
// The purpose of these tests is to act as a first line of defense // The purpose of these tests is to act as a first line of defense
// if something gets real screwy with our KCL ecosystem. // if something gets real screwy with our KCL ecosystem.
@ -27,7 +28,7 @@ const manifestJsonStr = await fs.readFile(
path.resolve(DIR_KCL_SAMPLES, 'manifest.json'), path.resolve(DIR_KCL_SAMPLES, 'manifest.json'),
'utf-8' 'utf-8'
) )
const manifest = JSON.parse(manifestJsonStr) const manifest: KclSampleFile[] = parseJson(manifestJsonStr)
process.chdir(DIR_KCL_SAMPLES) process.chdir(DIR_KCL_SAMPLES)

View File

@ -23,7 +23,7 @@ import {
getThemeColorForEngine, getThemeColorForEngine,
} from '@src/lib/theme' } from '@src/lib/theme'
import { reportRejection } from '@src/lib/trap' import { reportRejection } from '@src/lib/trap'
import { binaryToUuid, uuidv4 } from '@src/lib/utils' import { binaryToUuid, parseJson, uuidv4 } from '@src/lib/utils'
const pingIntervalMs = 1_000 const pingIntervalMs = 1_000
@ -390,7 +390,7 @@ class EngineConnection extends EventTarget {
this.websocket.addEventListener('open', this.onWebSocketOpen) this.websocket.addEventListener('open', this.onWebSocketOpen)
this.websocket?.addEventListener('message', ((event: MessageEvent) => { this.websocket?.addEventListener('message', ((event: MessageEvent) => {
const message: Models['WebSocketResponse_type'] = JSON.parse(event.data) const message: Models['WebSocketResponse_type'] = parseJson(event.data)
const pending = const pending =
this.engineCommandManager.pendingCommands[message.request_id || ''] this.engineCommandManager.pendingCommands[message.request_id || '']
if (!('resp' in message)) return if (!('resp' in message)) return
@ -862,7 +862,7 @@ class EngineConnection extends EventTarget {
) )
this.onDataChannelMessage = (event) => { this.onDataChannelMessage = (event) => {
const result: UnreliableResponses = JSON.parse(event.data) const result: UnreliableResponses = parseJson(event.data)
Object.values( Object.values(
this.engineCommandManager.unreliableSubscriptions[result.type] || this.engineCommandManager.unreliableSubscriptions[result.type] ||
{} {}
@ -976,7 +976,7 @@ class EngineConnection extends EventTarget {
return return
} }
const message: Models['WebSocketResponse_type'] = JSON.parse( const message: Models['WebSocketResponse_type'] = parseJson(
event.data event.data
) )
@ -1564,7 +1564,7 @@ export class EngineCommandManager extends EventTarget {
unreliableDataChannel.addEventListener( unreliableDataChannel.addEventListener(
'message', 'message',
(event: MessageEvent) => { (event: MessageEvent) => {
const result: UnreliableResponses = JSON.parse(event.data) const result: UnreliableResponses = parseJson(event.data)
Object.values( Object.values(
this.unreliableSubscriptions[result.type] || {} this.unreliableSubscriptions[result.type] || {}
).forEach( ).forEach(
@ -1608,7 +1608,7 @@ export class EngineCommandManager extends EventTarget {
message.request_id = binaryToUuid(message.request_id) message.request_id = binaryToUuid(message.request_id)
} }
} else { } else {
message = JSON.parse(event.data) message = parseJson(event.data)
} }
if (message === null) { if (message === null) {

View File

@ -40,7 +40,7 @@ import type { CoreDumpManager } from '@src/lib/coredump'
import openWindow from '@src/lib/openWindow' import openWindow from '@src/lib/openWindow'
import { Reason, err } from '@src/lib/trap' import { Reason, err } from '@src/lib/trap'
import type { DeepPartial } from '@src/lib/types' import type { DeepPartial } from '@src/lib/types'
import { isArray } from '@src/lib/utils' import { isArray, parseJson } from '@src/lib/utils'
import { import {
base64_decode, base64_decode,
change_kcl_settings, change_kcl_settings,
@ -217,9 +217,7 @@ export const parse = (code: string | Error): ParseResult | Error => {
let errs = splitErrors(parsed[1]) let errs = splitErrors(parsed[1])
return new ParseResult(parsed[0], errs.errors, errs.warnings) return new ParseResult(parsed[0], errs.errors, errs.warnings)
} catch (e: any) { } catch (e: any) {
// throw e const parsed: RustKclError = parseJson(e.toString())
console.error(e.toString())
const parsed: RustKclError = JSON.parse(e.toString())
return new KCLError( return new KCLError(
parsed.kind, parsed.kind,
parsed.msg, parsed.msg,
@ -381,7 +379,7 @@ export function sketchFromKclValue(
} }
export const errFromErrWithOutputs = (e: any): KCLError => { export const errFromErrWithOutputs = (e: any): KCLError => {
const parsed: KclErrorWithOutputs = JSON.parse(e.toString()) const parsed: KclErrorWithOutputs = parseJson(e.toString())
return new KCLError( return new KCLError(
parsed.error.kind, parsed.error.kind,
parsed.error.msg, parsed.error.msg,

View File

@ -3,7 +3,7 @@ import type { ApiError_type } from '@kittycad/lib/dist/types/src/models'
import type { Selections } from '@src/lib/selections' import type { Selections } from '@src/lib/selections'
import { engineCommandManager, kclManager } from '@src/lib/singletons' import { engineCommandManager, kclManager } from '@src/lib/singletons'
import { uuidv4 } from '@src/lib/utils' import { parseJson, uuidv4 } from '@src/lib/utils'
import type { CommandBarContext } from '@src/machines/commandBarMachine' import type { CommandBarContext } from '@src/machines/commandBarMachine'
export const disableDryRunWithRetry = async (numberOfRetries = 3) => { export const disableDryRunWithRetry = async (numberOfRetries = 3) => {
@ -54,7 +54,7 @@ export function parseEngineErrorMessage(engineError: string) {
return undefined return undefined
} }
const errors = JSON.parse(parts[1]) as ApiError_type[] const errors = parseJson<ApiError_type[]>(parts[1])
if (!errors[0]) { if (!errors[0]) {
return undefined return undefined
} }

View File

@ -26,6 +26,7 @@ import type { DeepPartial } from '@src/lib/types'
import type { ModuleType } from '@src/lib/wasm_lib_wrapper' import type { ModuleType } from '@src/lib/wasm_lib_wrapper'
import { getModule } from '@src/lib/wasm_lib_wrapper' import { getModule } from '@src/lib/wasm_lib_wrapper'
import type { Models } from '@kittycad/lib/dist/types/src' import type { Models } from '@kittycad/lib/dist/types/src'
import { parseJson } from '@src/lib/utils'
export default class RustContext { export default class RustContext {
private wasmInitFailed: boolean = true private wasmInitFailed: boolean = true
@ -140,7 +141,7 @@ export default class RustContext {
JSON.stringify(settings) JSON.stringify(settings)
) )
} catch (e: any) { } catch (e: any) {
const parsed: RustKclError = JSON.parse(e.toString()) const parsed: RustKclError = parseJson(e.toString())
toast.error(parsed.msg, { id: toastId }) toast.error(parsed.msg, { id: toastId })
return return
} }

View File

@ -60,6 +60,26 @@ export function isNonNullable<T>(val: T): val is NonNullable<T> {
return val !== null && val !== undefined return val !== null && val !== undefined
} }
/**
* Same as JSON.parse() but if it fails, includes the string that was attempted
* to be parsed in the error message. This is useful since a lot of times this
* is called on a string that isn't actually JSON, like another error message.
*
* You can also use the type parameter to assert the expected type of the parsed
* object.
*/
export function parseJson<T>(
text: string,
reviver?: (this: any, key: string, value: any) => any
): T {
try {
return JSON.parse(text, reviver)
} catch (e) {
// eslint-disable-next-line suggest-no-throw/suggest-no-throw
throw new Error(`Failed to parse JSON: ${text}`, { cause: e })
}
}
export function isOverlap(a: SourceRange, b: SourceRange) { export function isOverlap(a: SourceRange, b: SourceRange) {
const [startingRange, secondRange] = a[0] < b[0] ? [a, b] : [b, a] const [startingRange, secondRange] = a[0] < b[0] ? [a, b] : [b, a]
const [lastOfFirst, firstOfSecond] = [startingRange[1], secondRange[0]] const [lastOfFirst, firstOfSecond] = [startingRange[1], secondRange[0]]