Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions packages/core/src/common/Dev.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { bigintJsonNumberReplacer } from './index.js'

export namespace Dev {
export function assertDefined<T>(value: T): asserts value is Exclude<T, undefined> {
if (value === undefined) {
Expand Down Expand Up @@ -66,11 +68,11 @@ export namespace Dev {
if (value && typeof value === 'object') {
try {
const seen = new Set<object>()
return JSON.stringify(value, (_k, v) => {
return JSON.stringify(value, (k, v) => {
if (v && typeof v === 'object') {
return seen.has(v) ? '[Circular]' : (seen.add(v), v)
} else {
return v
return bigintJsonNumberReplacer(k, v)
}
})
} catch (ignored) {
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/common/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from './Dev.js'
export * from './externals/index.js'
export * from './json.js'
export * from './Logger.js'
export * from './Operations.js'
export * from './ReadonlyProxy.js'
Expand Down
53 changes: 53 additions & 0 deletions packages/core/src/common/json.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* Json replacer that writes bigints as a json string of the form `"$$type:bigint;$$value:91"`.
* Intended to be used with `bigintJsonLoslessReviver`
* @param _key The key at which the value lives
* @param value The value to encode
* @returns Replaced value
*/
export function bigintJsonLoslessReplacer(_key: string, value: any) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The spelling is Lossless btw

return typeof value === 'bigint'
? `$$type:bigint;$$value:${value}`
: value
}

/**
* Json reviver that revives bigints encoded by `bigintJsonLoslessReplacer`
* @param _key
* @param value
* @returns
*/
export function bigintJsonLoslessReviver(_key: string, value: any) {
return typeof value === 'string' && value.startsWith('$$type:bigint;$$value:')
? BigInt(value.substring(22))
: value
}

/**
* Json replacer that replaces bigints with raw json number literals, encoding the entire number.
* @param _key The key at which the value lives
* @param value The value to encode
* @returns Replaced value
*/
export function bigintJsonNumberReplacer(_key: string, value: any) {
return typeof value === 'bigint'
? (<any> JSON).rawJSON(value.toString())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Modern Typescript uses JSON as any. <any> JSON is not usually used and I had to look up the syntax lol

: value
}

/**
* Json reviver that when encountering a number will decide whether that number needs to be
* represented as a bigint in order to be losless. Uses normal numbers whenever possible or required.
* @param _key The key at which the value lives
* @param value The value that was read
* @param data Additional data, source includes the raw json value.
* @returns The javascript value
*/
export function bigintJsonNumberReviver(_key: string, value: any, data?: { source?: string }) {
return typeof value === 'number'
&& data?.source !== undefined
&& !data.source.includes('.')
&& value.toString() !== data.source
? BigInt(data.source)
: value
}
16 changes: 12 additions & 4 deletions packages/core/src/service/CacheService.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { TextDocument } from 'vscode-languageserver-textdocument'
import { Uri } from '../common/index.js'
import { bigintJsonLoslessReplacer, bigintJsonLoslessReviver, Uri } from '../common/index.js'
import type { PosRangeLanguageError } from '../source/index.js'
import type { UnlinkedSymbolTable } from '../symbol/index.js'
import { SymbolTable } from '../symbol/index.js'
Expand Down Expand Up @@ -130,8 +130,11 @@ export class CacheService {
try {
filePath = await this.getCacheFileUri()
this.project.logger.info(`[CacheService#load] symbolCachePath = ${filePath}`)
const cache =
(await fileUtil.readGzippedJson(this.project.externals, filePath)) as CacheFile
const cache = (await fileUtil.readGzippedJson(
this.project.externals,
filePath,
bigintJsonLoslessReviver,
)) as CacheFile
__profiler.task('Read File')
if (cache.version === LatestCacheVersion) {
this.checksums = cache.checksums
Expand Down Expand Up @@ -237,7 +240,12 @@ export class CacheService {
}
__profiler.task('Unlink Symbols')

await fileUtil.writeGzippedJson(this.project.externals, filePath, cache)
await fileUtil.writeGzippedJson(
this.project.externals,
filePath,
cache,
bigintJsonLoslessReplacer,
)
__profiler.task('Write File').finalize()

return true
Expand Down
29 changes: 23 additions & 6 deletions packages/core/src/service/fileUtil.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import type { Externals, FsLocation } from '../common/index.js'
import { bufferToString, Uri } from '../common/index.js'
import {
bigintJsonNumberReplacer,
bigintJsonNumberReviver,
bufferToString,
Uri,
} from '../common/index.js'

export type RootUriString = `${string}/`

Expand Down Expand Up @@ -265,7 +270,7 @@ export namespace fileUtil {
* @throws
*/
export async function readJson(externals: Externals, path: FsLocation): Promise<unknown> {
return JSON.parse(bufferToString(await readFile(externals, path)))
return JSON.parse(bufferToString(await readFile(externals, path)), bigintJsonNumberReviver)
}

/* istanbul ignore next */
Expand All @@ -279,7 +284,7 @@ export namespace fileUtil {
path: FsLocation,
data: any,
): Promise<void> {
return writeFile(externals, path, JSON.stringify(data))
return writeFile(externals, path, JSON.stringify(data, bigintJsonNumberReplacer))
}

/**
Expand Down Expand Up @@ -309,8 +314,15 @@ export namespace fileUtil {
/**
* @throws
*/
export async function readGzippedJson(externals: Externals, path: FsLocation): Promise<unknown> {
return JSON.parse(bufferToString(await readGzippedFile(externals, path)))
export async function readGzippedJson(
externals: Externals,
path: FsLocation,
reviver?: (this: any, key: string, value: any) => any,
): Promise<unknown> {
return JSON.parse(
bufferToString(await readGzippedFile(externals, path)),
reviver ?? bigintJsonNumberReviver,
)
}

/**
Expand All @@ -320,7 +332,12 @@ export namespace fileUtil {
externals: Externals,
path: FsLocation,
data: any,
replacer?: (this: any, key: string, value: any) => any,
): Promise<void> {
return writeGzippedFile(externals, path, JSON.stringify(data))
return writeGzippedFile(
externals,
path,
JSON.stringify(data, replacer ?? bigintJsonNumberReplacer),
)
}
}
7 changes: 5 additions & 2 deletions packages/core/src/symbol/Symbol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import rfdc from 'rfdc'
import type { TextDocument } from 'vscode-languageserver-textdocument'
import type { DeepReadonly } from '../common/index.js'
import { isIterable } from '../common/index.js'
import { bigintJsonLoslessReplacer, bigintJsonLoslessReviver } from '../common/json.js'
import type { RangeLike } from '../source/index.js'
import { Location, PositionRange, Range } from '../source/index.js'

Expand Down Expand Up @@ -582,6 +583,7 @@ export namespace SymbolTable {
if (parentSymbol) {
symbol.parentSymbol = parentSymbol
}

if (symbol.members) {
linkSymbolMap(symbol.members, symbol, category, path)
}
Expand Down Expand Up @@ -620,6 +622,7 @@ export namespace SymbolTable {
delete symbol.parentMap
delete symbol.parentSymbol
delete symbol.path

if (symbol.members) {
unlinkSymbolMap(symbol.members)
}
Expand All @@ -645,14 +648,14 @@ export namespace SymbolTable {
* a symbol table through the {@link deserialize} method.
*/
export function serialize(table: SymbolTable): string {
return JSON.stringify(unlink(table))
return JSON.stringify(unlink(table), bigintJsonLoslessReplacer)
}

/**
* @returns The symbol table represented by the string returned by the {@link serialize} method.
*/
export function deserialize(json: string): SymbolTable {
return link(JSON.parse(json))
return link(JSON.parse(json, bigintJsonLoslessReviver))
}
}

Expand Down
9 changes: 7 additions & 2 deletions packages/core/src/symbol/SymbolUtil.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { TextDocument } from 'vscode-languageserver-textdocument'
import type { DeepReadonly, ExternalEventEmitter, Externals } from '../common/index.js'
import {
bigintJsonNumberReplacer,
type DeepReadonly,
type ExternalEventEmitter,
type Externals,
} from '../common/index.js'
import type { AstNode } from '../node/index.js'
import type { RangeLike } from '../source/index.js'
import { Range } from '../source/index.js'
Expand Down Expand Up @@ -1301,7 +1306,7 @@ export namespace SymbolFormatter {
+ ` [${stringifyVisibility(symbol.visibility, symbol.visibilityRestriction)}]`,
)
if (symbol.data) {
ans.push(`${IndentChar}data: ${JSON.stringify(symbol.data)}`)
ans.push(`${IndentChar}data: ${JSON.stringify(symbol.data, bigintJsonNumberReplacer)}`)
}
if (symbol.desc) {
ans.push(`${IndentChar}description: ${symbol.desc}`)
Expand Down
34 changes: 17 additions & 17 deletions packages/core/test/parser/long.spec.ts.snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ exports[`long() > long() > long() > Parse '' 1`] = `
"start": 0,
"end": 0
},
"value": "0"
"value": 0
},
"errors": [
{
Expand All @@ -29,7 +29,7 @@ exports[`long() > long() > long() > Parse '+' 1`] = `
"start": 0,
"end": 1
},
"value": "0"
"value": 0
},
"errors": [
{
Expand All @@ -52,7 +52,7 @@ exports[`long() > long() > long() > Parse '+1' 1`] = `
"start": 0,
"end": 2
},
"value": "1"
"value": 1
},
"errors": []
}
Expand All @@ -66,7 +66,7 @@ exports[`long() > long() > long() > Parse '-1' 1`] = `
"start": 0,
"end": 2
},
"value": "-1"
"value": -1
},
"errors": []
}
Expand All @@ -80,7 +80,7 @@ exports[`long() > long() > long() > Parse '-123' 1`] = `
"start": 0,
"end": 4
},
"value": "-123"
"value": -123
},
"errors": []
}
Expand All @@ -94,7 +94,7 @@ exports[`long() > long() > long() > Parse '0123' 1`] = `
"start": 0,
"end": 4
},
"value": "123"
"value": 123
},
"errors": [
{
Expand All @@ -117,7 +117,7 @@ exports[`long() > long() > long() > Parse '123' 1`] = `
"start": 0,
"end": 3
},
"value": "123"
"value": 123
},
"errors": []
}
Expand All @@ -131,7 +131,7 @@ exports[`long() > long() > long() > Parse 'foo' 1`] = `
"start": 0,
"end": 0
},
"value": "0"
"value": 0
},
"errors": [
{
Expand Down Expand Up @@ -161,7 +161,7 @@ exports[`long() > long(min, max, onOutOfRange) > long(1, 6, true) > Parse '0' 1`
"start": 0,
"end": 1
},
"value": "0"
"value": 0
},
"errors": [
{
Expand All @@ -184,7 +184,7 @@ exports[`long() > long(min, max, onOutOfRange) > long(1, 6, true) > Parse '3' 1`
"start": 0,
"end": 1
},
"value": "3"
"value": 3
},
"errors": []
}
Expand All @@ -198,7 +198,7 @@ exports[`long() > long(min, max, onOutOfRange) > long(1, 6, true) > Parse '9' 1`
"start": 0,
"end": 1
},
"value": "9"
"value": 9
},
"errors": [
{
Expand All @@ -221,7 +221,7 @@ exports[`long() > long(min, max, onOutOfRange) > long(1, undefined, false) > Par
"start": 0,
"end": 1
},
"value": "0"
"value": 0
},
"errors": [
{
Expand All @@ -244,7 +244,7 @@ exports[`long() > long(min, max, onOutOfRange) > long(1, undefined, false) > Par
"start": 0,
"end": 1
},
"value": "3"
"value": 3
},
"errors": []
}
Expand All @@ -258,7 +258,7 @@ exports[`long() > long(min, max, onOutOfRange) > long(1, undefined, false) > Par
"start": 0,
"end": 1
},
"value": "9"
"value": 9
},
"errors": []
}
Expand All @@ -272,7 +272,7 @@ exports[`long() > long(min, max, onOutOfRange) > long(undefined, 6, false) > Par
"start": 0,
"end": 1
},
"value": "0"
"value": 0
},
"errors": []
}
Expand All @@ -286,7 +286,7 @@ exports[`long() > long(min, max, onOutOfRange) > long(undefined, 6, false) > Par
"start": 0,
"end": 1
},
"value": "3"
"value": 3
},
"errors": []
}
Expand All @@ -300,7 +300,7 @@ exports[`long() > long(min, max, onOutOfRange) > long(undefined, 6, false) > Par
"start": 0,
"end": 1
},
"value": "9"
"value": 9
},
"errors": [
{
Expand Down
Loading