Skip to content

Commit 6f24a1e

Browse files
committed
edit: Add per-field revisions for correct editing
Prevents fields from going back-in-time due to concurrent edits.
1 parent cdea3cb commit 6f24a1e

File tree

2 files changed

+45
-31
lines changed

2 files changed

+45
-31
lines changed

datacore.api.md

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -352,11 +352,11 @@ export class Datacore extends Component {
352352
// @internal
353353
initializer?: DatacoreInitializer;
354354
metadataCache: MetadataCache;
355-
off(evt: string, callback: (...data: any[]) => void): void;
355+
off(evt: string, callback: (...data: unknown[]) => void): void;
356356
offref(ref: EventRef): void;
357-
on(evt: "update", callback: (revision: number) => void, context?: any): EventRef;
358-
on(evt: "rename", callback: (newPath: string, oldPath: string) => void, context?: any): EventRef;
359-
on(evt: "initialized", callback: () => void, context?: any): EventRef;
357+
on(evt: "update", callback: (revision: number) => void, context?: unknown): EventRef;
358+
on(evt: "rename", callback: (newPath: string, oldPath: string) => void, context?: unknown): EventRef;
359+
on(evt: "initialized", callback: () => void, context?: unknown): EventRef;
360360
// Warning: (ae-forgotten-export) The symbol "LocalStorageCache" needs to be exported by the entry point index.d.ts
361361
//
362362
// @internal
@@ -589,7 +589,7 @@ export namespace Expressions {
589589
export namespace Extractors {
590590
export function frontmatter<T extends Indexable>(front: (object: T) => Record<string, FrontmatterEntry> | undefined): FieldExtractor<T>;
591591
export function inlineFields<T extends Indexable>(inlineMap: (object: T) => Record<string, InlineField> | undefined): FieldExtractor<T>;
592-
export function intrinsics<T>(except?: Set<string>): FieldExtractor<T>;
592+
export function intrinsics<T extends Indexable>(except?: Set<string>): FieldExtractor<T>;
593593
export function merge<T extends Fieldbearing>(...extractors: FieldExtractor<T>[]): FieldExtractor<T>;
594594
}
595595

@@ -621,7 +621,7 @@ export class Failure<T, E> {
621621
// @public
622622
export interface Field {
623623
key: string;
624-
provenance?: Provenance;
624+
provenance: Provenance;
625625
raw?: string;
626626
value: Literal;
627627
}
@@ -1373,11 +1373,17 @@ export type Provenance = {
13731373
type: "frontmatter";
13741374
file: string;
13751375
key: string;
1376+
revision: number;
13761377
} | {
13771378
type: "inline-field";
13781379
file: string;
13791380
line: number;
13801381
key: string;
1382+
revision: number;
1383+
} | {
1384+
type: "intrinsic";
1385+
file: string;
1386+
revision: number;
13811387
};
13821388

13831389
// @public

src/expression/field.ts

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ import { FrontmatterEntry } from "index/types/markdown";
88

99
/** The source of a field, used when determining what files to overwrite and how. */
1010
export type Provenance =
11-
| { type: "frontmatter"; file: string; key: string }
12-
| { type: "inline-field"; file: string; line: number; key: string };
11+
| { type: "frontmatter"; file: string; key: string; revision: number }
12+
| { type: "inline-field"; file: string; line: number; key: string; revision: number }
13+
| { type: "intrinsic"; file: string; revision: number; };
1314

1415
/**
1516
* General definition for a field. Provides the field key, value, as well as information on it's source and how it can be edited.
@@ -23,7 +24,7 @@ export interface Field {
2324
/** The raw value of the field before parsing, if relevant. */
2425
raw?: string;
2526
/** If present, describes where the field came from in precise detail, allowing the field to be edited. */
26-
provenance?: Provenance;
27+
provenance: Provenance;
2728
}
2829

2930
/** Metadata for objects which are annotated with fields. */
@@ -87,9 +88,9 @@ export namespace Extractors {
8788
}
8889

8990
/** Generate a list of fields for the given object, returning them as a list. */
90-
export function intrinsics<T>(except?: Set<string>): FieldExtractor<T> {
91+
export function intrinsics<T extends Indexable>(except?: Set<string>): FieldExtractor<T> {
9192
return (maybeObject: T, key?: string) => {
92-
const object = maybeObject as Record<string, unknown>;
93+
const object = maybeObject as Record<string, unknown> & Indexable;
9394
if (key == null) {
9495
const fields: Field[] = [];
9596

@@ -99,19 +100,21 @@ export namespace Extractors {
99100
fields.push({
100101
key,
101102
value: (object as Record<string, Literal>)[key],
103+
provenance: { type: "intrinsic", file: object.$file!, revision: object.$revision ?? 0 }
102104
});
103105
}
104106

105107
return fields;
106108
} else {
107109
// If key is directly present in object, just return it.
108110
if (key in object && isValidIntrinsic(object, key, except)) {
109-
return [
110-
{
111-
key,
112-
value: (object as Record<string, Literal>)[key],
113-
},
114-
] as Field[];
111+
const entry: Field = {
112+
key,
113+
value: (object as Record<string, Literal>)[key],
114+
provenance: { type: "intrinsic", file: object.$file!, revision: object.$revision ?? 0 }
115+
}
116+
117+
return [entry];
115118
}
116119

117120
return [];
@@ -137,7 +140,7 @@ export namespace Extractors {
137140
key: entry.key.toLowerCase(),
138141
value: entry.value,
139142
raw: entry.raw,
140-
provenance: { type: "frontmatter", file: object.$file!, key: entry.key },
143+
provenance: { type: "frontmatter", file: object.$file!, key: entry.key, revision: object.$revision ?? 0 },
141144
});
142145
}
143146

@@ -153,7 +156,7 @@ export namespace Extractors {
153156
key: key,
154157
value: entry.value,
155158
raw: entry.raw,
156-
provenance: { type: "frontmatter", file: object.$file!, key },
159+
provenance: { type: "frontmatter", file: object.$file!, key, revision: object.$revision ?? 0 },
157160
},
158161
];
159162
}
@@ -172,16 +175,19 @@ export namespace Extractors {
172175
const fields = [];
173176

174177
for (const field of Object.values(map)) {
178+
const provenance: Provenance = {
179+
type: "inline-field",
180+
file: object.$file!,
181+
line: field.position.line,
182+
key: field.key,
183+
revision: object.$revision ?? 0
184+
};
185+
175186
fields.push({
176187
key: field.key.toLowerCase(),
177188
value: field.value,
178189
raw: field.raw,
179-
provenance: {
180-
type: "inline-field",
181-
file: object.$file!,
182-
line: field.position.line,
183-
key: field.key,
184-
} as Provenance,
190+
provenance
185191
});
186192
}
187193

@@ -191,17 +197,19 @@ export namespace Extractors {
191197
if (!(key in map)) return [];
192198

193199
const field = map[key];
200+
const provenance: Provenance = {
201+
type: "inline-field",
202+
file: object.$file!,
203+
line: field.position.line,
204+
key: field.key,
205+
revision: object.$revision ?? 0
206+
};
194207
return [
195208
{
196209
key: key,
197210
value: field.value,
198211
raw: field.raw,
199-
provenance: {
200-
type: "inline-field",
201-
file: object.$file!,
202-
line: field.position.line,
203-
key: field.key,
204-
} as Provenance,
212+
provenance,
205213
},
206214
];
207215
}

0 commit comments

Comments
 (0)