gitsheets 0.22.4 → 1.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +21 -0
- package/bin/gitsheets +5 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +256 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/errors.d.ts +72 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +74 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/patch.d.ts +2 -0
- package/dist/patch.d.ts.map +1 -0
- package/dist/patch.js +39 -0
- package/dist/patch.js.map +1 -0
- package/dist/path-template/index.d.ts +42 -0
- package/dist/path-template/index.d.ts.map +1 -0
- package/dist/path-template/index.js +288 -0
- package/dist/path-template/index.js.map +1 -0
- package/dist/push-daemon.d.ts +53 -0
- package/dist/push-daemon.d.ts.map +1 -0
- package/dist/push-daemon.js +148 -0
- package/dist/push-daemon.js.map +1 -0
- package/dist/repository.d.ts +67 -0
- package/dist/repository.d.ts.map +1 -0
- package/dist/repository.js +322 -0
- package/dist/repository.js.map +1 -0
- package/dist/sheet.d.ts +107 -0
- package/dist/sheet.d.ts.map +1 -0
- package/dist/sheet.js +605 -0
- package/dist/sheet.js.map +1 -0
- package/dist/store.d.ts +41 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +49 -0
- package/dist/store.js.map +1 -0
- package/dist/toml.d.ts +11 -0
- package/dist/toml.d.ts.map +1 -0
- package/dist/toml.js +28 -0
- package/dist/toml.js.map +1 -0
- package/dist/transaction.d.ts +96 -0
- package/dist/transaction.d.ts.map +1 -0
- package/dist/transaction.js +227 -0
- package/dist/transaction.js.map +1 -0
- package/dist/validation.d.ts +37 -0
- package/dist/validation.d.ts.map +1 -0
- package/dist/validation.js +105 -0
- package/dist/validation.js.map +1 -0
- package/package.json +41 -35
- package/bin/cli.js +0 -61
- package/commands/edit.js +0 -90
- package/commands/normalize.js +0 -81
- package/commands/query.js +0 -206
- package/commands/read.js +0 -64
- package/commands/singer-target.js +0 -214
- package/commands/upsert.js +0 -260
- package/lib/GitSheets.js +0 -464
- package/lib/Repository.js +0 -88
- package/lib/Sheet.js +0 -625
- package/lib/errors.js +0 -21
- package/lib/hologit.js +0 -1
- package/lib/logger.js +0 -18
- package/lib/path/BaseComponent.js +0 -24
- package/lib/path/ExpressionComponent.js +0 -26
- package/lib/path/FieldComponent.js +0 -13
- package/lib/path/LiteralComponent.js +0 -12
- package/lib/path/Query.js +0 -18
- package/lib/path/Template.js +0 -214
- package/server.js +0 -120
package/dist/store.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { RecordLike } from './path-template/index.js';
|
|
2
|
+
import type { Repository } from './repository.js';
|
|
3
|
+
import { Sheet } from './sheet.js';
|
|
4
|
+
import type { TransactionOptions, TransactionResult } from './transaction.js';
|
|
5
|
+
import type { StandardSchemaV1 } from './validation.js';
|
|
6
|
+
/** Map of sheet name → Standard Schema validator. */
|
|
7
|
+
export type ValidatorMap = Readonly<Record<string, StandardSchemaV1<unknown, RecordLike>>>;
|
|
8
|
+
/** Extract a validator's output record type, or fall back to `RecordLike`. */
|
|
9
|
+
export type InferRecord<V> = V extends StandardSchemaV1<unknown, infer Output> ? Output extends RecordLike ? Output : RecordLike : RecordLike;
|
|
10
|
+
export interface OpenStoreOptions<V extends ValidatorMap = ValidatorMap> {
|
|
11
|
+
readonly validators?: V;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Typed view of a Store: every key in `V.validators` becomes a property
|
|
15
|
+
* typed as `Sheet<InferRecord<V[K]>>`. Plus `transact` for atomic bundles.
|
|
16
|
+
*
|
|
17
|
+
* Sheets present in `.gitsheets/` but absent from `validators` are not
|
|
18
|
+
* accessible via property access — they fall outside the typed surface.
|
|
19
|
+
* Use `Repository.openSheet(name)` for one-off un-typed access.
|
|
20
|
+
*/
|
|
21
|
+
export type Store<V extends ValidatorMap = ValidatorMap> = {
|
|
22
|
+
readonly [K in keyof V]: Sheet<InferRecord<V[K]>>;
|
|
23
|
+
} & {
|
|
24
|
+
readonly transact: StoreTransactFn<V>;
|
|
25
|
+
};
|
|
26
|
+
/** tx object passed into Store.transact's handler. */
|
|
27
|
+
export type StoreTx<V extends ValidatorMap = ValidatorMap> = {
|
|
28
|
+
readonly [K in keyof V]: Sheet<InferRecord<V[K]>>;
|
|
29
|
+
};
|
|
30
|
+
export type StoreTransactFn<V extends ValidatorMap = ValidatorMap> = <T>(opts: TransactionOptions, handler: (tx: StoreTx<V>) => Promise<T>) => Promise<TransactionResult<T>>;
|
|
31
|
+
/**
|
|
32
|
+
* Open a typed Store over the repo. Discovers every `.gitsheets/<name>.toml`
|
|
33
|
+
* and attaches per-sheet validators from `opts.validators`. Returns an object
|
|
34
|
+
* whose properties are the validated sheets, plus a `transact` method.
|
|
35
|
+
*
|
|
36
|
+
* Throws `ConfigError(config_missing)` if `validators` names a sheet that has
|
|
37
|
+
* no `.gitsheets/<name>.toml`. Sheets present on disk but absent from
|
|
38
|
+
* `validators` are accessible via `Repository.openSheet(name)`.
|
|
39
|
+
*/
|
|
40
|
+
export declare function openStore<V extends ValidatorMap = ValidatorMap>(repo: Repository, opts?: OpenStoreOptions<V>): Promise<Store<V>>;
|
|
41
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,KAAK,EAEV,kBAAkB,EAClB,iBAAiB,EAClB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC;AAExD,qDAAqD;AACrD,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC,CAAC,CAAC;AAE3F,8EAA8E;AAC9E,MAAM,MAAM,WAAW,CAAC,CAAC,IACvB,CAAC,SAAS,gBAAgB,CAAC,OAAO,EAAE,MAAM,MAAM,CAAC,GAC7C,MAAM,SAAS,UAAU,GACvB,MAAM,GACN,UAAU,GACZ,UAAU,CAAC;AAEjB,MAAM,WAAW,gBAAgB,CAAC,CAAC,SAAS,YAAY,GAAG,YAAY;IACrE,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;CACzB;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,KAAK,CAAC,CAAC,SAAS,YAAY,GAAG,YAAY,IAAI;IACzD,QAAQ,EAAE,CAAC,IAAI,MAAM,CAAC,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAClD,GAAG;IACF,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC,CAAC,CAAC,CAAC;CACvC,CAAC;AAEF,sDAAsD;AACtD,MAAM,MAAM,OAAO,CAAC,CAAC,SAAS,YAAY,GAAG,YAAY,IAAI;IAC3D,QAAQ,EAAE,CAAC,IAAI,MAAM,CAAC,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAClD,CAAC;AAEF,MAAM,MAAM,eAAe,CAAC,CAAC,SAAS,YAAY,GAAG,YAAY,IAAI,CAAC,CAAC,EACrE,IAAI,EAAE,kBAAkB,EACxB,OAAO,EAAE,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,KACpC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC;AAEnC;;;;;;;;GAQG;AACH,wBAAsB,SAAS,CAAC,CAAC,SAAS,YAAY,GAAG,YAAY,EACnE,IAAI,EAAE,UAAU,EAChB,IAAI,GAAE,gBAAgB,CAAC,CAAC,CAAM,GAC7B,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CA+CnB"}
|
package/dist/store.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
// Store — typed wrapper over Repository.openSheets with per-sheet validators.
|
|
2
|
+
// See specs/api/store.md.
|
|
3
|
+
import { ConfigError } from './errors.js';
|
|
4
|
+
/**
|
|
5
|
+
* Open a typed Store over the repo. Discovers every `.gitsheets/<name>.toml`
|
|
6
|
+
* and attaches per-sheet validators from `opts.validators`. Returns an object
|
|
7
|
+
* whose properties are the validated sheets, plus a `transact` method.
|
|
8
|
+
*
|
|
9
|
+
* Throws `ConfigError(config_missing)` if `validators` names a sheet that has
|
|
10
|
+
* no `.gitsheets/<name>.toml`. Sheets present on disk but absent from
|
|
11
|
+
* `validators` are accessible via `Repository.openSheet(name)`.
|
|
12
|
+
*/
|
|
13
|
+
export async function openStore(repo, opts = {}) {
|
|
14
|
+
const sheetsBase = await repo.openSheets();
|
|
15
|
+
const declared = new Set(Object.keys(sheetsBase));
|
|
16
|
+
// Verify the validator map only names sheets that exist.
|
|
17
|
+
if (opts.validators) {
|
|
18
|
+
for (const name of Object.keys(opts.validators)) {
|
|
19
|
+
if (!declared.has(name)) {
|
|
20
|
+
throw new ConfigError('config_missing', `Store opens with validators.${name}, but .gitsheets/${name}.toml is not declared`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
// Re-open each sheet with its validator (the validator changes per-sheet
|
|
25
|
+
// behavior — easier to re-open than mutate the discovery result).
|
|
26
|
+
const sheets = {};
|
|
27
|
+
for (const name of declared) {
|
|
28
|
+
const validator = opts.validators?.[name];
|
|
29
|
+
if (validator !== undefined) {
|
|
30
|
+
sheets[name] = await repo.openSheet(name, { validator });
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
sheets[name] = sheetsBase[name];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const transact = (txOpts, handler) => {
|
|
37
|
+
const innerHandler = async (rawTx) => {
|
|
38
|
+
const txObj = {};
|
|
39
|
+
for (const name of declared) {
|
|
40
|
+
const validator = opts.validators?.[name];
|
|
41
|
+
txObj[name] = rawTx.sheet(name, validator !== undefined ? { validator } : undefined);
|
|
42
|
+
}
|
|
43
|
+
return handler(txObj);
|
|
44
|
+
};
|
|
45
|
+
return repo.transact(txOpts, innerHandler);
|
|
46
|
+
};
|
|
47
|
+
return Object.assign(Object.create(null), sheets, { transact });
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,0BAA0B;AAE1B,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAkD1C;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,IAAgB,EAChB,OAA4B,EAAE;IAE9B,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;IAC3C,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC;IAElD,yDAAyD;IACzD,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;QACpB,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;YAChD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBACxB,MAAM,IAAI,WAAW,CACnB,gBAAgB,EAChB,+BAA+B,IAAI,oBAAoB,IAAI,uBAAuB,CACnF,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED,yEAAyE;IACzE,kEAAkE;IAClE,MAAM,MAAM,GAA0B,EAAE,CAAC;IACzC,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC5B,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC,CAAC;QAC1C,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC5B,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC;QAC3D,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,IAAI,CAAE,CAAC;QACnC,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAuB,CACnC,MAA0B,EAC1B,OAAuC,EACR,EAAE;QACjC,MAAM,YAAY,GAA0B,KAAK,EAAE,KAAK,EAAE,EAAE;YAC1D,MAAM,KAAK,GAA0B,EAAE,CAAC;YACxC,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;gBAC5B,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC,IAAI,CAAC,CAAC;gBAC1C,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,KAAK,CACvB,IAAI,EACJ,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,SAAS,CACpD,CAAC;YACJ,CAAC;YACD,OAAO,OAAO,CAAC,KAA8B,CAAC,CAAC;QACjD,CAAC,CAAC;QACF,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAC7C,CAAC,CAAC;IAEF,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,CAAa,CAAC;AAC9E,CAAC"}
|
package/dist/toml.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type RecordLike = Record<string, unknown>;
|
|
2
|
+
/**
|
|
3
|
+
* Serialize a record to canonical TOML — deep-sorted keys for byte-stable output.
|
|
4
|
+
*
|
|
5
|
+
* Array fields are NOT sorted here; sheet-level normalization rules
|
|
6
|
+
* (`[gitsheet.fields.<name>.sort]`) handle that before this is called.
|
|
7
|
+
*/
|
|
8
|
+
export declare function stringifyRecord(record: RecordLike): string;
|
|
9
|
+
export declare function parseToml(content: string): RecordLike;
|
|
10
|
+
export declare function parseConfigToml(content: string, sourcePath: string): RecordLike;
|
|
11
|
+
//# sourceMappingURL=toml.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toml.d.ts","sourceRoot":"","sources":["../src/toml.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAUjD;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAG1D;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CAErD;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,UAAU,CAU/E"}
|
package/dist/toml.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// TOML serialization helpers with canonical key sorting.
|
|
2
|
+
// See specs/behaviors/normalization.md for the byte-stable normalization rules.
|
|
3
|
+
import * as TOML from '@iarna/toml';
|
|
4
|
+
import sortKeys from 'sort-keys';
|
|
5
|
+
import { ConfigError } from './errors.js';
|
|
6
|
+
const toml = TOML;
|
|
7
|
+
/**
|
|
8
|
+
* Serialize a record to canonical TOML — deep-sorted keys for byte-stable output.
|
|
9
|
+
*
|
|
10
|
+
* Array fields are NOT sorted here; sheet-level normalization rules
|
|
11
|
+
* (`[gitsheet.fields.<name>.sort]`) handle that before this is called.
|
|
12
|
+
*/
|
|
13
|
+
export function stringifyRecord(record) {
|
|
14
|
+
const sorted = sortKeys(record, { deep: true });
|
|
15
|
+
return toml.stringify(sorted);
|
|
16
|
+
}
|
|
17
|
+
export function parseToml(content) {
|
|
18
|
+
return toml.parse(content);
|
|
19
|
+
}
|
|
20
|
+
export function parseConfigToml(content, sourcePath) {
|
|
21
|
+
try {
|
|
22
|
+
return parseToml(content);
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
throw new ConfigError('config_invalid', `failed to parse TOML at ${sourcePath}: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=toml.js.map
|
package/dist/toml.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toml.js","sourceRoot":"","sources":["../src/toml.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,gFAAgF;AAEhF,OAAO,KAAK,IAAI,MAAM,aAAa,CAAC;AACpC,OAAO,QAAQ,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAU1C,MAAM,IAAI,GAAG,IAA6B,CAAC;AAE3C;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAAC,MAAkB;IAChD,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAA4B,CAAC;IAC3E,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,OAAe;IACvC,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAAe,EAAE,UAAkB;IACjE,IAAI,CAAC;QACH,OAAO,SAAS,CAAC,OAAO,CAAC,CAAC;IAC5B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,WAAW,CACnB,gBAAgB,EAChB,2BAA2B,UAAU,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EAC5F,EAAE,KAAK,EAAE,GAAG,EAAE,CACf,CAAC;IACJ,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
|
+
import type { Repo as HologitRepo, TreeObject, Workspace } from 'hologit';
|
|
3
|
+
import { RefError } from './errors.js';
|
|
4
|
+
import type { RecordLike } from './path-template/index.js';
|
|
5
|
+
import type { Sheet } from './sheet.js';
|
|
6
|
+
import type { StandardSchemaV1 } from './validation.js';
|
|
7
|
+
export interface Author {
|
|
8
|
+
readonly name: string;
|
|
9
|
+
readonly email: string;
|
|
10
|
+
}
|
|
11
|
+
export interface TransactionOptions {
|
|
12
|
+
/** Ref name or commit hash to parent the commit on; defaults to current HEAD. */
|
|
13
|
+
readonly parent?: string;
|
|
14
|
+
/** Ref name to update on commit; default: parent if it's a branch, null if a hash. */
|
|
15
|
+
readonly branch?: string;
|
|
16
|
+
/** Commit author; defaults to git config user.name/email. */
|
|
17
|
+
readonly author?: Author;
|
|
18
|
+
/** Commit committer; defaults to author. */
|
|
19
|
+
readonly committer?: Author;
|
|
20
|
+
/** Commit subject + body. First line is the subject. */
|
|
21
|
+
readonly message: string;
|
|
22
|
+
/** Git-style trailers appended per `git interpret-trailers`. */
|
|
23
|
+
readonly trailers?: Readonly<Record<string, string>>;
|
|
24
|
+
}
|
|
25
|
+
export interface TransactionResult<T> {
|
|
26
|
+
readonly value: T;
|
|
27
|
+
readonly commitHash: string | null;
|
|
28
|
+
readonly treeHash: string | null;
|
|
29
|
+
readonly ref: string | null;
|
|
30
|
+
readonly parentCommitHash: string | null;
|
|
31
|
+
}
|
|
32
|
+
export type TransactionHandler<T> = (tx: Transaction) => Promise<T>;
|
|
33
|
+
export declare const transactionContext: AsyncLocalStorage<Transaction>;
|
|
34
|
+
/**
|
|
35
|
+
* In-process mutex serializing transactions on a single Repository.
|
|
36
|
+
* Concurrent callers from independent async contexts queue; nested
|
|
37
|
+
* repo.transact attempts (same async context) throw before acquiring.
|
|
38
|
+
*/
|
|
39
|
+
export declare class Mutex {
|
|
40
|
+
#private;
|
|
41
|
+
acquire(): Promise<() => void>;
|
|
42
|
+
}
|
|
43
|
+
export declare class Transaction {
|
|
44
|
+
#private;
|
|
45
|
+
/**
|
|
46
|
+
* @internal — Transactions are created by Repository.transact (or
|
|
47
|
+
* Store.transact). Consumers do not construct Transaction directly; the
|
|
48
|
+
* constructor is exported only so the type is available for typing
|
|
49
|
+
* handler parameters.
|
|
50
|
+
*/
|
|
51
|
+
constructor(opts: {
|
|
52
|
+
hologitRepo: HologitRepo;
|
|
53
|
+
workspace: Workspace;
|
|
54
|
+
parentCommitHash: string | null;
|
|
55
|
+
parentRef: string | null;
|
|
56
|
+
branchRef: string | null;
|
|
57
|
+
author: Author;
|
|
58
|
+
committer: Author;
|
|
59
|
+
message: string;
|
|
60
|
+
trailers: Readonly<Record<string, string>>;
|
|
61
|
+
sheetFactory: <T extends RecordLike = RecordLike>(name: string, workspace: Workspace, tree: TreeObject, validator?: StandardSchemaV1<unknown, T>) => Sheet<T>;
|
|
62
|
+
});
|
|
63
|
+
get tree(): TreeObject;
|
|
64
|
+
get parentCommitHash(): string | null;
|
|
65
|
+
get parentRef(): string | null;
|
|
66
|
+
get branchRef(): string | null;
|
|
67
|
+
/** Marker used by Sheet to record that a mutation happened in this tx. */
|
|
68
|
+
markMutated(): void;
|
|
69
|
+
/**
|
|
70
|
+
* Returns a Sheet whose writes route through this transaction's private tree.
|
|
71
|
+
* `opts.validator` (optional) attaches a Standard Schema validator — used by
|
|
72
|
+
* Store.transact to thread per-sheet validators through to tx scope.
|
|
73
|
+
*/
|
|
74
|
+
sheet<T extends RecordLike = RecordLike>(name: string, opts?: {
|
|
75
|
+
validator?: StandardSchemaV1<unknown, T>;
|
|
76
|
+
}): Sheet<T>;
|
|
77
|
+
/**
|
|
78
|
+
* Finalize the transaction. Returns the commit hash + tree hash, or nulls if
|
|
79
|
+
* no mutations occurred. Throws TransactionError(parent_moved) on optimistic
|
|
80
|
+
* concurrency conflict. After finalize the transaction is closed.
|
|
81
|
+
*/
|
|
82
|
+
finalize<T>(value: T): Promise<TransactionResult<T>>;
|
|
83
|
+
/** Called by Repository on handler throw. Marks the transaction closed. */
|
|
84
|
+
discard(): void;
|
|
85
|
+
static normalizeOptions(opts: TransactionOptions): {
|
|
86
|
+
parent: string | undefined;
|
|
87
|
+
branch: string | undefined;
|
|
88
|
+
author: Author | undefined;
|
|
89
|
+
committer: Author | undefined;
|
|
90
|
+
message: string;
|
|
91
|
+
trailers: Readonly<Record<string, string>>;
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
export declare function resolveAuthor(gitDir: string, explicit: Author | undefined): Promise<Author>;
|
|
95
|
+
export declare function refNotFound(ref: string): RefError;
|
|
96
|
+
//# sourceMappingURL=transaction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transaction.d.ts","sourceRoot":"","sources":["../src/transaction.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
// Transaction — scopes a set of sheet mutations to a single commit.
|
|
2
|
+
// See specs/api/transaction.md + specs/behaviors/transactions.md.
|
|
3
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
4
|
+
import { execFile } from 'node:child_process';
|
|
5
|
+
import { promisify } from 'node:util';
|
|
6
|
+
import { RefError, TransactionError } from './errors.js';
|
|
7
|
+
const exec = promisify(execFile);
|
|
8
|
+
// Active transaction context — used to detect nested repo.transact attempts.
|
|
9
|
+
export const transactionContext = new AsyncLocalStorage();
|
|
10
|
+
const HTTP_HEADER_KEY_RE = /^[A-Z][a-z0-9]*(-[A-Z][a-z0-9]*)*$|^[A-Z][a-z]+$/;
|
|
11
|
+
const TRAILER_VALUE_RE = /[\r\n]/;
|
|
12
|
+
function validateTrailers(trailers) {
|
|
13
|
+
if (!trailers)
|
|
14
|
+
return;
|
|
15
|
+
for (const [key, value] of Object.entries(trailers)) {
|
|
16
|
+
if (!HTTP_HEADER_KEY_RE.test(key)) {
|
|
17
|
+
throw new TransactionError('commit_failed', `trailer key ${JSON.stringify(key)} does not match HTTP-header style (e.g., "Subject-Id", "Action")`);
|
|
18
|
+
}
|
|
19
|
+
if (typeof value !== 'string' || TRAILER_VALUE_RE.test(value)) {
|
|
20
|
+
throw new TransactionError('commit_failed', `trailer ${JSON.stringify(key)} has invalid value (must be string with no newlines): ${JSON.stringify(value)}`);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function formatCommitMessage(subject, trailers) {
|
|
25
|
+
// The `subject` arg is the full message string — it may already contain a body.
|
|
26
|
+
const body = subject.trimEnd();
|
|
27
|
+
if (!trailers || Object.keys(trailers).length === 0) {
|
|
28
|
+
return body + '\n';
|
|
29
|
+
}
|
|
30
|
+
const lines = Object.entries(trailers).map(([k, v]) => `${k}: ${v}`).join('\n');
|
|
31
|
+
return `${body}\n\n${lines}\n`;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* In-process mutex serializing transactions on a single Repository.
|
|
35
|
+
* Concurrent callers from independent async contexts queue; nested
|
|
36
|
+
* repo.transact attempts (same async context) throw before acquiring.
|
|
37
|
+
*/
|
|
38
|
+
export class Mutex {
|
|
39
|
+
#locked = false;
|
|
40
|
+
#queue = [];
|
|
41
|
+
async acquire() {
|
|
42
|
+
if (!this.#locked) {
|
|
43
|
+
this.#locked = true;
|
|
44
|
+
return () => this.#release();
|
|
45
|
+
}
|
|
46
|
+
return new Promise((resolve) => {
|
|
47
|
+
this.#queue.push(() => resolve(() => this.#release()));
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
#release() {
|
|
51
|
+
const next = this.#queue.shift();
|
|
52
|
+
if (next) {
|
|
53
|
+
next();
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
this.#locked = false;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export class Transaction {
|
|
61
|
+
#hologitRepo;
|
|
62
|
+
#workspace;
|
|
63
|
+
#parentCommitHash;
|
|
64
|
+
#parentRef;
|
|
65
|
+
#branchRef;
|
|
66
|
+
#author;
|
|
67
|
+
#committer;
|
|
68
|
+
#message;
|
|
69
|
+
#trailers;
|
|
70
|
+
/** Function the Repository injects so Transaction.sheet() can build Sheet instances. */
|
|
71
|
+
#sheetFactory;
|
|
72
|
+
#closed = false;
|
|
73
|
+
#anyMutation = false;
|
|
74
|
+
/**
|
|
75
|
+
* @internal — Transactions are created by Repository.transact (or
|
|
76
|
+
* Store.transact). Consumers do not construct Transaction directly; the
|
|
77
|
+
* constructor is exported only so the type is available for typing
|
|
78
|
+
* handler parameters.
|
|
79
|
+
*/
|
|
80
|
+
constructor(opts) {
|
|
81
|
+
this.#hologitRepo = opts.hologitRepo;
|
|
82
|
+
this.#workspace = opts.workspace;
|
|
83
|
+
this.#parentCommitHash = opts.parentCommitHash;
|
|
84
|
+
this.#parentRef = opts.parentRef;
|
|
85
|
+
this.#branchRef = opts.branchRef;
|
|
86
|
+
this.#author = opts.author;
|
|
87
|
+
this.#committer = opts.committer;
|
|
88
|
+
this.#message = opts.message;
|
|
89
|
+
this.#trailers = opts.trailers;
|
|
90
|
+
this.#sheetFactory = opts.sheetFactory;
|
|
91
|
+
}
|
|
92
|
+
get tree() {
|
|
93
|
+
return this.#workspace.root;
|
|
94
|
+
}
|
|
95
|
+
get parentCommitHash() {
|
|
96
|
+
return this.#parentCommitHash;
|
|
97
|
+
}
|
|
98
|
+
get parentRef() {
|
|
99
|
+
return this.#parentRef;
|
|
100
|
+
}
|
|
101
|
+
get branchRef() {
|
|
102
|
+
return this.#branchRef;
|
|
103
|
+
}
|
|
104
|
+
/** Marker used by Sheet to record that a mutation happened in this tx. */
|
|
105
|
+
markMutated() {
|
|
106
|
+
this.#anyMutation = true;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Returns a Sheet whose writes route through this transaction's private tree.
|
|
110
|
+
* `opts.validator` (optional) attaches a Standard Schema validator — used by
|
|
111
|
+
* Store.transact to thread per-sheet validators through to tx scope.
|
|
112
|
+
*/
|
|
113
|
+
sheet(name, opts) {
|
|
114
|
+
if (this.#closed) {
|
|
115
|
+
throw new TransactionError('transaction_closed', 'transaction is already closed — obtain a fresh Transaction via repo.transact');
|
|
116
|
+
}
|
|
117
|
+
return this.#sheetFactory(name, this.#workspace, this.#workspace.root, opts?.validator);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Finalize the transaction. Returns the commit hash + tree hash, or nulls if
|
|
121
|
+
* no mutations occurred. Throws TransactionError(parent_moved) on optimistic
|
|
122
|
+
* concurrency conflict. After finalize the transaction is closed.
|
|
123
|
+
*/
|
|
124
|
+
async finalize(value) {
|
|
125
|
+
this.#closed = true;
|
|
126
|
+
if (!this.#anyMutation) {
|
|
127
|
+
return {
|
|
128
|
+
value,
|
|
129
|
+
commitHash: null,
|
|
130
|
+
treeHash: null,
|
|
131
|
+
ref: null,
|
|
132
|
+
parentCommitHash: this.#parentCommitHash,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
// Optimistic concurrency: re-check the parent ref hasn't moved.
|
|
136
|
+
if (this.#parentRef !== null) {
|
|
137
|
+
const current = await this.#hologitRepo.resolveRef(this.#parentRef);
|
|
138
|
+
if (current !== this.#parentCommitHash) {
|
|
139
|
+
throw new TransactionError('parent_moved', `parent ref ${this.#parentRef} moved during transaction (expected ${this.#parentCommitHash ?? 'null'}, found ${current ?? 'null'})`);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
const gitDir = this.#hologitRepo.gitDir;
|
|
143
|
+
const treeHash = await this.#workspace.root.write();
|
|
144
|
+
const message = formatCommitMessage(this.#message, this.#trailers);
|
|
145
|
+
let commitHash;
|
|
146
|
+
try {
|
|
147
|
+
const args = ['commit-tree', treeHash, '-m', message];
|
|
148
|
+
if (this.#parentCommitHash) {
|
|
149
|
+
args.push('-p', this.#parentCommitHash);
|
|
150
|
+
}
|
|
151
|
+
const env = {
|
|
152
|
+
...process.env,
|
|
153
|
+
GIT_AUTHOR_NAME: this.#author.name,
|
|
154
|
+
GIT_AUTHOR_EMAIL: this.#author.email,
|
|
155
|
+
GIT_COMMITTER_NAME: this.#committer.name,
|
|
156
|
+
GIT_COMMITTER_EMAIL: this.#committer.email,
|
|
157
|
+
};
|
|
158
|
+
const { stdout } = await exec('git', args, { cwd: gitDir, env });
|
|
159
|
+
commitHash = stdout.trim();
|
|
160
|
+
}
|
|
161
|
+
catch (err) {
|
|
162
|
+
throw new TransactionError('commit_failed', `git commit-tree failed: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
|
|
163
|
+
}
|
|
164
|
+
if (this.#branchRef !== null) {
|
|
165
|
+
try {
|
|
166
|
+
const args = ['update-ref', this.#branchRef, commitHash];
|
|
167
|
+
if (this.#parentCommitHash) {
|
|
168
|
+
args.push(this.#parentCommitHash);
|
|
169
|
+
}
|
|
170
|
+
await exec('git', args, { cwd: gitDir });
|
|
171
|
+
}
|
|
172
|
+
catch (err) {
|
|
173
|
+
throw new TransactionError('commit_failed', `git update-ref ${this.#branchRef} failed: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return {
|
|
177
|
+
value,
|
|
178
|
+
commitHash,
|
|
179
|
+
treeHash,
|
|
180
|
+
ref: this.#branchRef,
|
|
181
|
+
parentCommitHash: this.#parentCommitHash,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
/** Called by Repository on handler throw. Marks the transaction closed. */
|
|
185
|
+
discard() {
|
|
186
|
+
this.#closed = true;
|
|
187
|
+
}
|
|
188
|
+
static normalizeOptions(opts) {
|
|
189
|
+
validateTrailers(opts.trailers);
|
|
190
|
+
return {
|
|
191
|
+
parent: opts.parent,
|
|
192
|
+
branch: opts.branch,
|
|
193
|
+
author: opts.author,
|
|
194
|
+
committer: opts.committer ?? opts.author,
|
|
195
|
+
message: opts.message,
|
|
196
|
+
trailers: opts.trailers ?? {},
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
// --- Author resolution from git config ---
|
|
201
|
+
let anonymousWarned = false;
|
|
202
|
+
export async function resolveAuthor(gitDir, explicit) {
|
|
203
|
+
if (explicit)
|
|
204
|
+
return explicit;
|
|
205
|
+
try {
|
|
206
|
+
const [name, email] = await Promise.all([
|
|
207
|
+
exec('git', ['config', 'user.name'], { cwd: gitDir }).then((r) => r.stdout.trim()),
|
|
208
|
+
exec('git', ['config', 'user.email'], { cwd: gitDir }).then((r) => r.stdout.trim()),
|
|
209
|
+
]);
|
|
210
|
+
if (name && email) {
|
|
211
|
+
return { name, email };
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
catch {
|
|
215
|
+
// fall through to anonymous default
|
|
216
|
+
}
|
|
217
|
+
if (!anonymousWarned) {
|
|
218
|
+
anonymousWarned = true;
|
|
219
|
+
process.stderr.write('gitsheets: no commit author configured (set git config user.name + user.email, or pass opts.author); falling back to Anonymous <anonymous@gitsheets.local>\n');
|
|
220
|
+
}
|
|
221
|
+
return { name: 'Anonymous', email: 'anonymous@gitsheets.local' };
|
|
222
|
+
}
|
|
223
|
+
// --- RefError helpers ---
|
|
224
|
+
export function refNotFound(ref) {
|
|
225
|
+
return new RefError('ref_not_found', `ref not found: ${ref}`);
|
|
226
|
+
}
|
|
227
|
+
//# sourceMappingURL=transaction.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transaction.js","sourceRoot":"","sources":["../src/transaction.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type ValidateFunction } from 'ajv';
|
|
2
|
+
export type JSONSchema = Record<string, unknown>;
|
|
3
|
+
export interface StandardSchemaPathSegment {
|
|
4
|
+
readonly key: string | number;
|
|
5
|
+
}
|
|
6
|
+
export interface StandardSchemaIssue {
|
|
7
|
+
readonly message: string;
|
|
8
|
+
readonly path?: ReadonlyArray<string | number | StandardSchemaPathSegment>;
|
|
9
|
+
}
|
|
10
|
+
export interface StandardSchemaSuccess<Output> {
|
|
11
|
+
readonly value: Output;
|
|
12
|
+
readonly issues?: undefined;
|
|
13
|
+
}
|
|
14
|
+
export interface StandardSchemaFailure {
|
|
15
|
+
readonly issues: ReadonlyArray<StandardSchemaIssue>;
|
|
16
|
+
}
|
|
17
|
+
export type StandardSchemaResult<Output> = StandardSchemaSuccess<Output> | StandardSchemaFailure;
|
|
18
|
+
export interface StandardSchemaV1<Input = unknown, Output = Input> {
|
|
19
|
+
readonly '~standard': {
|
|
20
|
+
readonly version: 1;
|
|
21
|
+
readonly vendor: string;
|
|
22
|
+
readonly validate: (value: unknown) => StandardSchemaResult<Output> | Promise<StandardSchemaResult<Output>>;
|
|
23
|
+
};
|
|
24
|
+
/** unused — only here so consumers' generic type can flow Input/Output. */
|
|
25
|
+
readonly __types__?: {
|
|
26
|
+
input: Input;
|
|
27
|
+
output: Output;
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export declare function compileSchema(schema: JSONSchema, sourcePath: string): ValidateFunction;
|
|
31
|
+
export declare function validateRecord(opts: {
|
|
32
|
+
record: Record<string, unknown>;
|
|
33
|
+
schema: JSONSchema | null;
|
|
34
|
+
schemaSourcePath?: string;
|
|
35
|
+
validator?: StandardSchemaV1 | undefined;
|
|
36
|
+
}): Promise<Record<string, unknown>>;
|
|
37
|
+
//# sourceMappingURL=validation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAKA,OAAO,EAAO,KAAK,gBAAgB,EAAoB,MAAM,KAAK,CAAC;AAOnE,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAKjD,MAAM,WAAW,yBAAyB;IACxC,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;CAC/B;AACD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,aAAa,CAAC,MAAM,GAAG,MAAM,GAAG,yBAAyB,CAAC,CAAC;CAC5E;AACD,MAAM,WAAW,qBAAqB,CAAC,MAAM;IAC3C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,CAAC;CAC7B;AACD,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAC;CACrD;AACD,MAAM,MAAM,oBAAoB,CAAC,MAAM,IAAI,qBAAqB,CAAC,MAAM,CAAC,GAAG,qBAAqB,CAAC;AACjG,MAAM,WAAW,gBAAgB,CAAC,KAAK,GAAG,OAAO,EAAE,MAAM,GAAG,KAAK;IAC/D,QAAQ,CAAC,WAAW,EAAE;QACpB,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC;QACpB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;QACxB,QAAQ,CAAC,QAAQ,EAAE,CACjB,KAAK,EAAE,OAAO,KACX,oBAAoB,CAAC,MAAM,CAAC,GAAG,OAAO,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC,CAAC;KAC3E,CAAC;IACF,2EAA2E;IAC3E,QAAQ,CAAC,SAAS,CAAC,EAAE;QAAE,KAAK,EAAE,KAAK,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CACvD;AAiBD,wBAAgB,aAAa,CAAC,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,GAAG,gBAAgB,CAgBtF;AAID,wBAAsB,cAAc,CAAC,IAAI,EAAE;IACzC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,MAAM,EAAE,UAAU,GAAG,IAAI,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,EAAE,gBAAgB,GAAG,SAAS,CAAC;CAC1C,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAoCnC"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// Validation pipeline — JSON Schema via ajv, then optional Standard Schema.
|
|
2
|
+
// See specs/behaviors/validation.md.
|
|
3
|
+
// ajv v8 named-exports Ajv as a class; addFormats is a default-exported plugin
|
|
4
|
+
// in a CJS package — NodeNext gives us the namespace, so we pull `.default`.
|
|
5
|
+
import { Ajv } from 'ajv';
|
|
6
|
+
import * as addFormatsNs from 'ajv-formats';
|
|
7
|
+
const addFormats = addFormatsNs.default;
|
|
8
|
+
import { ConfigError, ValidationError } from './errors.js';
|
|
9
|
+
// --- ajv setup ---
|
|
10
|
+
// Compiled validators are cached per schema-identity (object reference) so a
|
|
11
|
+
// Sheet's `Sheet.readConfig` returning the same schema object hits the cache.
|
|
12
|
+
const COMPILED_CACHE = new WeakMap();
|
|
13
|
+
let sharedAjv = null;
|
|
14
|
+
function getAjv() {
|
|
15
|
+
if (!sharedAjv) {
|
|
16
|
+
sharedAjv = new Ajv({ strict: true, allErrors: true, $data: false });
|
|
17
|
+
addFormats(sharedAjv);
|
|
18
|
+
}
|
|
19
|
+
return sharedAjv;
|
|
20
|
+
}
|
|
21
|
+
export function compileSchema(schema, sourcePath) {
|
|
22
|
+
const cached = COMPILED_CACHE.get(schema);
|
|
23
|
+
if (cached)
|
|
24
|
+
return cached;
|
|
25
|
+
const ajv = getAjv();
|
|
26
|
+
let compiled;
|
|
27
|
+
try {
|
|
28
|
+
compiled = ajv.compile(schema);
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
throw new ConfigError('config_invalid', `${sourcePath}: [gitsheet.schema] failed to compile: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
|
|
32
|
+
}
|
|
33
|
+
COMPILED_CACHE.set(schema, compiled);
|
|
34
|
+
return compiled;
|
|
35
|
+
}
|
|
36
|
+
// --- Public validate ---
|
|
37
|
+
export async function validateRecord(opts) {
|
|
38
|
+
const issues = [];
|
|
39
|
+
let value = opts.record;
|
|
40
|
+
if (opts.schema) {
|
|
41
|
+
const compiled = compileSchema(opts.schema, opts.schemaSourcePath ?? '<schema>');
|
|
42
|
+
const ok = compiled(value);
|
|
43
|
+
if (!ok) {
|
|
44
|
+
for (const err of compiled.errors ?? []) {
|
|
45
|
+
issues.push(ajvErrorToIssue(err));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (issues.length > 0) {
|
|
50
|
+
throw new ValidationError('validation_failed', 'record failed JSON Schema validation', {
|
|
51
|
+
issues,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
if (opts.validator) {
|
|
55
|
+
const result = await opts.validator['~standard'].validate(value);
|
|
56
|
+
if (isFailure(result)) {
|
|
57
|
+
for (const issue of result.issues) {
|
|
58
|
+
issues.push(standardIssueToIssue(issue));
|
|
59
|
+
}
|
|
60
|
+
throw new ValidationError('validation_failed', 'record failed Standard Schema validation', { issues });
|
|
61
|
+
}
|
|
62
|
+
value = result.value;
|
|
63
|
+
}
|
|
64
|
+
return value;
|
|
65
|
+
}
|
|
66
|
+
function ajvErrorToIssue(err) {
|
|
67
|
+
const path = err.instancePath
|
|
68
|
+
? err.instancePath.split('/').slice(1).map(unescapeJsonPointer)
|
|
69
|
+
: [];
|
|
70
|
+
const issue = {
|
|
71
|
+
path,
|
|
72
|
+
message: err.message ?? 'validation failed',
|
|
73
|
+
source: 'json-schema',
|
|
74
|
+
};
|
|
75
|
+
if (err.schemaPath !== undefined) {
|
|
76
|
+
Object.assign(issue, { schemaPath: err.schemaPath });
|
|
77
|
+
}
|
|
78
|
+
if (err.keyword !== undefined) {
|
|
79
|
+
Object.assign(issue, { code: err.keyword });
|
|
80
|
+
}
|
|
81
|
+
return issue;
|
|
82
|
+
}
|
|
83
|
+
function unescapeJsonPointer(segment) {
|
|
84
|
+
return segment.replace(/~1/g, '/').replace(/~0/g, '~');
|
|
85
|
+
}
|
|
86
|
+
function standardIssueToIssue(issue) {
|
|
87
|
+
const path = [];
|
|
88
|
+
for (const seg of issue.path ?? []) {
|
|
89
|
+
if (typeof seg === 'string' || typeof seg === 'number') {
|
|
90
|
+
path.push(String(seg));
|
|
91
|
+
}
|
|
92
|
+
else if (seg && typeof seg === 'object' && 'key' in seg) {
|
|
93
|
+
path.push(String(seg.key));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
path,
|
|
98
|
+
message: issue.message,
|
|
99
|
+
source: 'standard-schema',
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function isFailure(result) {
|
|
103
|
+
return 'issues' in result && Array.isArray(result.issues);
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=validation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"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"}
|