enso/app/gui2/ydoc-server/serialization.ts
Kaz Wesley f88bd90ebb
Refactor for YJs AST (#8840)
Some refactoring separated from #8825 for easier review.

# Important Notes
**ID types**

The new *synchronization IDs* will replace `ExprId` for `Ast` references in frontend logic. `ExprId` (now called `ExternalId`) is now used only for module serialization and engine communication. The graph database will maintain an index that is used to translate at the boundaries. For now, this translation is implemented as a type cast, as the IDs have the same values until the next PR.

- `AstId`: Identifies an `Ast` node.
- `NodeId`: A subtype of `AstId`.
- `ExternalId`: UUID used for serialization and engine communication.

**Other changes**:

- Immediate validation of `Owned` usage.
- Eliminate `Ast.RawCode`.
- Prepare to remove `IdMap` from yjsModel.
2024-01-24 19:22:05 +00:00

50 lines
1.6 KiB
TypeScript

/** Translation of `yjsModel` types to and from the `fileFormat` representation. */
import * as json from 'lib0/json'
import { ExternalId, IdMap, sourceRangeFromKey } from '../shared/yjsModel'
import * as fileFormat from './fileFormat'
export function deserializeIdMap(idMapJson: string) {
const idMapMeta = fileFormat.tryParseIdMapOrFallback(idMapJson)
const idMap = new IdMap()
for (const [{ index, size }, id] of idMapMeta) {
const range = [index.value, index.value + size.value]
if (typeof range[0] !== 'number' || typeof range[1] !== 'number') {
console.error(`Invalid range for id ${id}:`, range)
continue
}
idMap.insertKnownId([index.value, index.value + size.value], id as ExternalId)
}
return idMap
}
export function serializeIdMap(map: IdMap): string {
map.validate()
return json.stringify(idMapToArray(map))
}
function idMapToArray(map: IdMap): fileFormat.IdMapEntry[] {
const entries: fileFormat.IdMapEntry[] = []
map.entries().forEach(([rangeBuffer, id]) => {
const decoded = sourceRangeFromKey(rangeBuffer)
const index = decoded[0]
const endIndex = decoded[1]
if (index == null || endIndex == null) return
const size = endIndex - index
entries.push([{ index: { value: index }, size: { value: size } }, id])
})
entries.sort(idMapCmp)
return entries
}
function idMapCmp(a: fileFormat.IdMapEntry, b: fileFormat.IdMapEntry) {
const val1 = a[0]?.index?.value ?? 0
const val2 = b[0]?.index?.value ?? 0
if (val1 === val2) {
const size1 = a[0]?.size.value ?? 0
const size2 = b[0]?.size.value ?? 0
return size1 - size2
}
return val1 - val2
}