Add Prettier formatting and Gitea Actions CI (format, typecheck, test, build)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017Qxbkp4tA7G5SCWjzWuxmE
This commit is contained in:
@@ -62,8 +62,7 @@ export function isIndexValue(v: unknown): v is IndexValue {
|
||||
|
||||
function makeCodec(sep: string): IndexValueCodec {
|
||||
const sepCode = sep.charCodeAt(0)
|
||||
const digits =
|
||||
sepCode < 0x30 ? '0123456789abcdef' : Array.from({ length: 16 }, (_, i) => String.fromCharCode(sepCode + 1 + i)).join('')
|
||||
const digits = sepCode < 0x30 ? '0123456789abcdef' : Array.from({ length: 16 }, (_, i) => String.fromCharCode(sepCode + 1 + i)).join('')
|
||||
const digitValue = new Map<string, number>([...digits].map((d, i) => [d, i]))
|
||||
const TAG_NULL = digits[0]!
|
||||
const TAG_FALSE = digits[1]!
|
||||
|
||||
@@ -39,7 +39,8 @@ export interface EventSourcedDocumentStorageOptions {
|
||||
}
|
||||
|
||||
/** Stored projection of one document. */
|
||||
export type Projection = { state: Doc; version: number; commit: number; deleted?: undefined } | { deleted: true; version: number; commit: number; state?: undefined }
|
||||
export type Projection =
|
||||
{ state: Doc; version: number; commit: number; deleted?: undefined } | { deleted: true; version: number; commit: number; state?: undefined }
|
||||
|
||||
interface DocContext {
|
||||
readonly driver: KVDriver
|
||||
@@ -120,7 +121,16 @@ export class EventSourcedDocumentNodeImpl<S extends Spec = AnySpec> implements E
|
||||
child<K extends KeyOf<S>>(key: K): EventSourcedDocumentNodeImpl<ChildOf<S, K>> {
|
||||
const seg = toSegment(key)
|
||||
const esc = escapeSegment(seg, this.#ctx.sep)
|
||||
return new EventSourcedDocumentNodeImpl(this.#ctx, this.#ev.child(seg), this.#ev, [...this.path, seg], this.#prefix + esc, esc, this.#ctx.registry.trie.step(this.#state, seg), this.#childIdx)
|
||||
return new EventSourcedDocumentNodeImpl(
|
||||
this.#ctx,
|
||||
this.#ev.child(seg),
|
||||
this.#ev,
|
||||
[...this.path, seg],
|
||||
this.#prefix + esc,
|
||||
esc,
|
||||
this.#ctx.registry.trie.step(this.#state, seg),
|
||||
this.#childIdx,
|
||||
)
|
||||
}
|
||||
|
||||
as<S2 extends Spec>(): EventSourcedDocumentNodeImpl<S2> {
|
||||
@@ -356,7 +366,9 @@ export class EventSourcedDocumentNodeImpl<S extends Spec = AnySpec> implements E
|
||||
throw err
|
||||
}
|
||||
const releases = oldClaims ? [...oldClaims.keys()].filter((k) => !newClaims!.has(k)) : []
|
||||
const projection: Projection = next ? { state: next, version: result.version, commit: result.commit } : { deleted: true, version: result.version, commit: result.commit }
|
||||
const projection: Projection = next
|
||||
? { state: next, version: result.version, commit: result.commit }
|
||||
: { deleted: true, version: result.version, commit: result.commit }
|
||||
await this.#writeProjection(t, cur, next, projection, releases)
|
||||
return next
|
||||
}
|
||||
@@ -515,7 +527,13 @@ export class EventSourcedDocumentNodeImpl<S extends Spec = AnySpec> implements E
|
||||
/** Filter with values replaced by `?`, for de-duplicating warnings. */
|
||||
function filterShape(f: unknown): unknown {
|
||||
if (Array.isArray(f)) return f.map(filterShape)
|
||||
if (isPlainObject(f)) return Object.fromEntries(Object.entries(f).map(([k, v]) => [k, k.startsWith('$') && (k === '$and' || k === '$or' || k === '$not') ? filterShape(v) : isPlainObject(v) ? filterShape(v) : '?']))
|
||||
if (isPlainObject(f))
|
||||
return Object.fromEntries(
|
||||
Object.entries(f).map(([k, v]) => [
|
||||
k,
|
||||
k.startsWith('$') && (k === '$and' || k === '$or' || k === '$not') ? filterShape(v) : isPlainObject(v) ? filterShape(v) : '?',
|
||||
]),
|
||||
)
|
||||
return '?'
|
||||
}
|
||||
|
||||
|
||||
@@ -12,10 +12,7 @@ export interface UpdateSpec {
|
||||
}
|
||||
|
||||
/** Stored document events: resolved deltas, never operators, so replay is deterministic. */
|
||||
export type DocEvent =
|
||||
| { op: 'set'; doc: Doc }
|
||||
| { op: 'patch'; set?: Record<string, unknown>; unset?: string[] }
|
||||
| { op: 'delete' }
|
||||
export type DocEvent = { op: 'set'; doc: Doc } | { op: 'patch'; set?: Record<string, unknown>; unset?: string[] } | { op: 'delete' }
|
||||
|
||||
export interface Patch {
|
||||
set: Record<string, unknown>
|
||||
@@ -44,8 +41,7 @@ export function resolveUpdate(state: Doc, spec: UpdateSpec): Patch {
|
||||
if (!Array.isArray(cur)) throw new TypeError(`${op} on non-array field "${path}"`)
|
||||
return cur
|
||||
}
|
||||
const eachOf = (v: unknown): unknown[] =>
|
||||
isPlainObject(v) && Object.keys(v).length === 1 && Array.isArray(v.$each) ? (v.$each as unknown[]) : [v]
|
||||
const eachOf = (v: unknown): unknown[] => (isPlainObject(v) && Object.keys(v).length === 1 && Array.isArray(v.$each) ? (v.$each as unknown[]) : [v])
|
||||
|
||||
for (const [path, v] of Object.entries(spec.$set ?? {})) {
|
||||
touch(path)
|
||||
|
||||
@@ -81,7 +81,8 @@ export function unsetPath(doc: Doc, path: string): void {
|
||||
if (typeof v !== 'object' || v === null) return
|
||||
}
|
||||
const last = segs.at(-1)!
|
||||
if (Array.isArray(v) && /^\d+$/.test(last)) v[Number(last)] = null // Mongo semantics: keep positions
|
||||
if (Array.isArray(v) && /^\d+$/.test(last))
|
||||
v[Number(last)] = null // Mongo semantics: keep positions
|
||||
else if (isPlainObject(v)) delete v[last]
|
||||
}
|
||||
|
||||
|
||||
+4
-1
@@ -30,7 +30,10 @@ export class UniqueConstraintError extends PotentialStorageError {
|
||||
|
||||
/** The driver lacks an optional capability required by the requested feature. */
|
||||
export class CapabilityError extends PotentialStorageError {
|
||||
constructor(readonly capability: string, detail?: string) {
|
||||
constructor(
|
||||
readonly capability: string,
|
||||
detail?: string,
|
||||
) {
|
||||
super(`Driver lacks capability "${capability}"${detail ? `: ${detail}` : ''}`)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -400,4 +400,3 @@ export class KVStorage<S extends Spec = AnySpec> extends KVNode<S> {
|
||||
super({ driver, sep, registry, readRepair: opts.readRepair ?? true }, [], '', '', registry.trie.rootState, undefined)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ export interface SortedMap<V> {
|
||||
keys(range: { gte?: string; lt?: string; reverse?: boolean }): IterableIterator<string>
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sorted chunks of at most `maxChunk` keys (split in half on overflow) plus a `Map` for values.
|
||||
* Inserts and deletes cost O(log n + maxChunk); iteration is O(1) per step while the map
|
||||
|
||||
+2
-3
@@ -22,9 +22,8 @@ export type KeyString<S> = `${KeyOf<S>}`
|
||||
export type EntryOf<S> = { [K in KeyOf<S>]: [K, ValueOf<ChildOf<S, K>>] }[KeyOf<S>]
|
||||
|
||||
/** `[key, value]` as yielded at runtime (string keys). Dynamic levels collapse to `[string, V]`. */
|
||||
export type StringEntryOf<S> = string extends KeyOf<S>
|
||||
? [string, ValueOf<ChildOf<S, KeyOf<S> & string>>]
|
||||
: { [K in KeyOf<S>]: [`${K}`, ValueOf<ChildOf<S, K>>] }[KeyOf<S>]
|
||||
export type StringEntryOf<S> =
|
||||
string extends KeyOf<S> ? [string, ValueOf<ChildOf<S, KeyOf<S> & string>>] : { [K in KeyOf<S>]: [`${K}`, ValueOf<ChildOf<S, K>>] }[KeyOf<S>]
|
||||
|
||||
/** A dynamic level of children with values `V`, each with children `C`. */
|
||||
export type Many<V, C extends Record<string, Spec> = {}> = { children: { [id: string]: { value: V; children: C } } }
|
||||
|
||||
Reference in New Issue
Block a user