tsondb 0.21.4 → 0.21.8
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/dist/src/node/bin/tsondb.js +10 -4
- package/dist/src/node/index.d.ts +12 -3
- package/dist/src/node/index.js +29 -14
- package/dist/src/node/renderers/jsonschema/index.d.ts +1 -1
- package/dist/src/node/renderers/jsonschema/index.js +2 -2
- package/dist/src/node/renderers/jsonschema/render.js +4 -6
- package/dist/src/node/renderers/ts/index.d.ts +1 -1
- package/dist/src/node/renderers/ts/index.js +2 -2
- package/dist/src/node/renderers/ts/render.js +11 -21
- package/dist/src/node/schema/detached.d.ts +1 -1
- package/dist/src/node/schema/detached.js +0 -1
- package/dist/src/node/schema/dsl/declarations/Decl.d.ts +3 -3
- package/dist/src/node/schema/dsl/declarations/Decl.js +1 -1
- package/dist/src/node/schema/dsl/declarations/EntityDecl.d.ts +2 -2
- package/dist/src/node/schema/dsl/declarations/EntityDecl.js +1 -1
- package/dist/src/node/schema/dsl/declarations/EnumDecl.d.ts +2 -3
- package/dist/src/node/schema/dsl/declarations/SingletonEntityDecl.d.ts +1 -1
- package/dist/src/node/schema/dsl/declarations/TypeAliasDecl.d.ts +1 -1
- package/dist/src/node/schema/dsl/index.d.ts +1 -1
- package/dist/src/node/schema/dsl/types/ChildEntitiesType.d.ts +1 -1
- package/dist/src/node/schema/dsl/types/ChildEntitiesType.js +0 -1
- package/dist/src/node/schema/dsl/types/IncludeIdentifierType.d.ts +1 -1
- package/dist/src/node/schema/dsl/types/IncludeIdentifierType.js +0 -1
- package/dist/src/node/schema/dsl/types/NestedEntityMapType.d.ts +1 -1
- package/dist/src/node/schema/dsl/types/NestedEntityMapType.js +0 -1
- package/dist/src/node/schema/dsl/types/ObjectType.js +1 -1
- package/dist/src/node/schema/helpers.d.ts +4 -4
- package/dist/src/node/schema/helpers.js +8 -11
- package/dist/src/node/schema/index.d.ts +2 -2
- package/dist/src/node/schema/index.js +4 -3
- package/dist/src/node/schema/treeOperations/format.js +2 -1
- package/dist/src/node/schema/treeOperations/serialization.d.ts +19 -19
- package/dist/src/node/schema/treeOperations/serialization.js +0 -18
- package/dist/src/node/schema/treeOperations/typeResolution.d.ts +9 -11
- package/dist/src/node/schema/treeOperations/typeResolution.js +0 -7
- package/dist/src/node/schema/treeOperations/validation.d.ts +1 -1
- package/dist/src/node/schema/treeOperations/validation.js +5 -6
- package/dist/src/node/schema/validation/options.js +2 -1
- package/dist/src/node/server/api/declarations.js +2 -2
- package/dist/src/node/server/api/git.js +2 -2
- package/dist/src/node/server/index.d.ts +2 -2
- package/dist/src/node/server/index.js +2 -2
- package/dist/src/node/server/utils/query.js +1 -1
- package/dist/src/node/transaction.d.ts +2 -2
- package/dist/src/node/transaction.js +0 -2
- package/dist/src/node/utils/childInstances.d.ts +1 -1
- package/dist/src/node/utils/childInstances.js +3 -2
- package/dist/src/node/utils/customConstraints.d.ts +1 -1
- package/dist/src/node/utils/customConstraints.js +0 -1
- package/dist/src/node/utils/databaseInMemory.js +16 -18
- package/dist/src/node/utils/databaseOnDisk.js +8 -0
- package/dist/src/node/utils/displayName.d.ts +1 -1
- package/dist/src/node/utils/displayName.js +24 -29
- package/dist/src/node/utils/files.d.ts +1 -1
- package/dist/src/node/utils/files.js +1 -2
- package/dist/src/node/utils/path.js +2 -1
- package/dist/src/node/utils/references.d.ts +1 -1
- package/dist/src/node/utils/references.js +6 -5
- package/dist/src/node/utils/unique.d.ts +1 -1
- package/dist/src/node/utils/unique.js +8 -17
- package/dist/src/shared/schema/declarations/Declaration.d.ts +1 -1
- package/dist/src/shared/schema/declarations/Declaration.js +0 -1
- package/dist/src/shared/schema/declarations/EnumDecl.js +5 -7
- package/dist/src/shared/schema/types/EnumType.js +2 -2
- package/dist/src/shared/schema/types/NestedEntityMapType.d.ts +1 -2
- package/dist/src/shared/schema/utils/keyPath.js +14 -14
- package/dist/src/shared/schema/utils/sortOrder.js +1 -1
- package/dist/src/shared/utils/git.js +6 -1
- package/dist/src/shared/utils/render.js +3 -3
- package/dist/src/shared/utils/translation.js +15 -16
- package/dist/src/shared/utils/validation.js +4 -4
- package/dist/src/shared/validation/date.js +2 -2
- package/dist/src/shared/validation/identifier.js +1 -1
- package/dist/src/shared/validation/number.js +3 -3
- package/dist/src/shared/validation/object.js +1 -1
- package/dist/src/shared/validation/string.js +1 -1
- package/dist/src/web/web.js +1140 -1212
- package/package.json +19 -18
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { readFile, rm, writeFile } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
import {} from "../schema/dsl/index.js";
|
|
4
3
|
import { formatValue } from "../schema/treeOperations/format.js";
|
|
5
4
|
export const getFileNameForId = (id) => `${id}.json`;
|
|
6
5
|
export const getSingletonFileName = (entityName) => `${entityName}.json`;
|
|
@@ -20,4 +19,4 @@ export const writeSingletonInstance = (dataRoot, entity, instance, formatterOpti
|
|
|
20
19
|
});
|
|
21
20
|
export const deleteInstance = (dataRoot, entityName, id) => rm(getPathToInstance(dataRoot, entityName, id));
|
|
22
21
|
export const deleteSingletonInstance = (dataRoot, entityName) => rm(getPathToSingletonInstance(dataRoot, entityName));
|
|
23
|
-
export const formatInstance = (entity, instanceContent, options) => JSON.stringify(formatValue(entity.type.value, instanceContent, {}, options), undefined, 2)
|
|
22
|
+
export const formatInstance = (entity, instanceContent, options) => `${JSON.stringify(formatValue(entity.type.value, instanceContent, {}, options), undefined, 2)}\n`;
|
|
@@ -1,2 +1,3 @@
|
|
|
1
1
|
import { sep } from "node:path";
|
|
2
|
-
|
|
2
|
+
const specialDirStartRegex = new RegExp(`^\\.\\.?\\${sep}`, "u");
|
|
3
|
+
export const ensureSpecialDirStart = (path) => specialDirStartRegex.test(path) ? path : `./${path}`;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { SerializedDecl } from "../../shared/schema/declarations/Declaration.ts";
|
|
2
2
|
import type { InstanceContent } from "../../shared/utils/instances.ts";
|
|
3
3
|
import type { AnyEntityMap, GetEntityByName, RegisteredEntityMap } from "../schema/generatedTypeHelpers.ts";
|
|
4
|
-
import {
|
|
4
|
+
import type { DatabaseInMemory } from "./databaseInMemory.ts";
|
|
5
5
|
/**
|
|
6
6
|
* A mapping from instance IDs to the list of instance IDs that reference them.
|
|
7
7
|
*
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { removeAt } from "@elyukai/utils/array/modify";
|
|
2
2
|
import { difference } from "@elyukai/utils/array/sets";
|
|
3
3
|
import { isOk } from "@elyukai/utils/result";
|
|
4
|
-
import { resolve } from "node:path";
|
|
4
|
+
import { resolve as resolvePath } from "node:path";
|
|
5
5
|
import { getReferencesForSerializedSingletonEntityDecl, } from "../../shared/schema/declarations/SingletonEntityDecl.js";
|
|
6
6
|
import { getReferences } from "../schema/treeOperations/references.js";
|
|
7
|
-
import {} from "./databaseInMemory.js";
|
|
8
7
|
import { WorkerPool } from "./workers.js";
|
|
9
8
|
export const isReferencedByOtherInstances = (referencesToInstances, instanceId, otherInstancesToDelete) => {
|
|
10
9
|
const allInstancesToDelete = [instanceId, ...(otherInstancesToDelete ?? [])];
|
|
@@ -17,8 +16,10 @@ const addReference = (acc, reference, instanceId) => ({
|
|
|
17
16
|
const addReferences = (acc, references, instanceId) => references.reduce((acc1, reference) => addReference(acc1, reference, instanceId), acc);
|
|
18
17
|
const mergeReferences = (acc, toMerge) => {
|
|
19
18
|
for (const instanceId in toMerge) {
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
if (Object.hasOwn(toMerge, instanceId)) {
|
|
20
|
+
;
|
|
21
|
+
(acc[instanceId] ??= []).push(...(toMerge[instanceId] ?? []));
|
|
22
|
+
}
|
|
22
23
|
}
|
|
23
24
|
return acc;
|
|
24
25
|
};
|
|
@@ -36,7 +37,7 @@ const removeReference = (acc, reference, instanceId) => {
|
|
|
36
37
|
};
|
|
37
38
|
const removeReferences = (acc, references, instanceId) => references.reduce((acc1, reference) => removeReference(acc1, reference, instanceId), acc);
|
|
38
39
|
export const getReferencesToInstances = async (databaseInMemory, serializedDeclarationsByName) => {
|
|
39
|
-
const pool = new WorkerPool(6,
|
|
40
|
+
const pool = new WorkerPool(6, resolvePath(import.meta.dirname, "./referencesWorker.js"), serializedDeclarationsByName);
|
|
40
41
|
const separateResults = await Promise.all(databaseInMemory.getAllInstances().map(([entityName, instances]) => new Promise((resolve, reject) => {
|
|
41
42
|
try {
|
|
42
43
|
pool.runTask({ entityName, instances }, result => {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type Result } from "@elyukai/utils/result";
|
|
2
2
|
import type { InstanceContainer, InstanceContainerOverview } from "../../shared/utils/instances.ts";
|
|
3
3
|
import type { EntityDecl } from "../schema/dsl/index.ts";
|
|
4
|
-
import {
|
|
4
|
+
import type { DatabaseInMemory } from "./databaseInMemory.ts";
|
|
5
5
|
/**
|
|
6
6
|
* Checks all unique constraints for the provided entity and its instances.
|
|
7
7
|
*
|
|
@@ -4,22 +4,13 @@ import { deepEqual } from "@elyukai/utils/equality";
|
|
|
4
4
|
import { error, isError, mapError, ok } from "@elyukai/utils/result";
|
|
5
5
|
import { getValueAtKeyPath, getValueAtKeyPathIfDefined, renderKeyPath, } from "../../shared/schema/utils/keyPath.js";
|
|
6
6
|
import { UniqueConstraintError } from "../../shared/utils/unique.js";
|
|
7
|
-
import {} from "./databaseInMemory.js";
|
|
8
7
|
const printUniqueConstraint = (constraint, values) => (Array.isArray(constraint) ? constraint : [constraint])
|
|
9
8
|
.map((elem, i) => "keyPath" in elem
|
|
10
9
|
? renderKeyPath(elem.keyPath) +
|
|
11
10
|
(elem.keyPathFallback ? "|" + renderKeyPath(elem.keyPathFallback) : "")
|
|
12
|
-
: renderKeyPath(elem.entityMapKeyPath)
|
|
13
|
-
|
|
14
|
-
(
|
|
15
|
-
"]." +
|
|
16
|
-
(elem.keyPathInEntityMapFallback
|
|
17
|
-
? "(" +
|
|
18
|
-
renderKeyPath(elem.keyPathInEntityMap) +
|
|
19
|
-
"|" +
|
|
20
|
-
renderKeyPath(elem.keyPathInEntityMapFallback) +
|
|
21
|
-
")"
|
|
22
|
-
: renderKeyPath(elem.keyPathInEntityMap)))
|
|
11
|
+
: `${renderKeyPath(elem.entityMapKeyPath)}[${Array.isArray(values[i]) ? values[i][0] : "..."}].${elem.keyPathInEntityMapFallback
|
|
12
|
+
? `(${renderKeyPath(elem.keyPathInEntityMap)}|${renderKeyPath(elem.keyPathInEntityMapFallback)})`
|
|
13
|
+
: renderKeyPath(elem.keyPathInEntityMap)}`)
|
|
23
14
|
.join("+");
|
|
24
15
|
/**
|
|
25
16
|
* Checks all unique constraints for the provided entity and its instances.
|
|
@@ -28,7 +19,7 @@ const printUniqueConstraint = (constraint, values) => (Array.isArray(constraint)
|
|
|
28
19
|
* `AggregateError` if there are any violations of any unique constraint.
|
|
29
20
|
*/
|
|
30
21
|
export const checkUniqueConstraintsForEntity = (entity, instances, instanceOverviews) => {
|
|
31
|
-
const
|
|
22
|
+
const constraintErrorsList = [];
|
|
32
23
|
const constraints = entity.uniqueConstraints ?? [];
|
|
33
24
|
for (const [constraintIndex, constraint] of constraints.entries()) {
|
|
34
25
|
const normalizedConstraint = Array.isArray(constraint) ? constraint : [constraint];
|
|
@@ -54,17 +45,17 @@ export const checkUniqueConstraintsForEntity = (entity, instances, instanceOverv
|
|
|
54
45
|
})).map((row) => [id, row]));
|
|
55
46
|
const duplicates = anySameIndices(index, (a, b) => deepEqual(a[1], b[1]));
|
|
56
47
|
if (duplicates.length > 0) {
|
|
57
|
-
|
|
48
|
+
constraintErrorsList.push([
|
|
58
49
|
constraintIndex,
|
|
59
50
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- Indices returned by anySameIndices must exist
|
|
60
51
|
duplicates.map(duplicateSet => duplicateSet.map(rowIndex => index[rowIndex])),
|
|
61
52
|
]);
|
|
62
53
|
}
|
|
63
54
|
}
|
|
64
|
-
if (
|
|
65
|
-
return error(new AggregateError(
|
|
55
|
+
if (constraintErrorsList.length > 0) {
|
|
56
|
+
return error(new AggregateError(constraintErrorsList.flatMap(([constraintIndex, constraintErrors]) => constraintErrors.map(constraintError => new UniqueConstraintError(
|
|
66
57
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- constraint must be present
|
|
67
|
-
`for unique constraint ${printUniqueConstraint(constraints[constraintIndex],
|
|
58
|
+
`for unique constraint ${printUniqueConstraint(constraints[constraintIndex], constraintError[0][1])}:`, constraintError.map(row => {
|
|
68
59
|
const instanceOverview = instanceOverviews.find(o => o.id === row[0]);
|
|
69
60
|
return instanceOverview ? `"${instanceOverview.displayName}" (${row[0]})` : row[0];
|
|
70
61
|
})))), `in entity "${entity.name}"`));
|
|
@@ -2,7 +2,7 @@ import type { BaseNode } from "../Node.ts";
|
|
|
2
2
|
import type { SerializedTypeParameter } from "../TypeParameter.ts";
|
|
3
3
|
import type { SerializedEnumCaseDecl } from "../types/EnumType.ts";
|
|
4
4
|
import type { SerializedMemberDecl } from "../types/ObjectType.ts";
|
|
5
|
-
import {
|
|
5
|
+
import type { SerializedType } from "../types/Type.ts";
|
|
6
6
|
import type { SerializedEntityDecl } from "./EntityDecl.ts";
|
|
7
7
|
import type { SerializedEnumDecl } from "./EnumDecl.ts";
|
|
8
8
|
import type { SerializedSingletonEntityDecl } from "./SingletonEntityDecl.ts";
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import {} from "../types/Type.js";
|
|
2
1
|
export const getSerializedTypeArgumentsRecord = (decl, args) => Object.fromEntries(
|
|
3
2
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
4
3
|
args.slice(0, decl.parameters.length).map((arg, i) => [decl.parameters[i].name, arg]));
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { NodeKind, } from "../Node.js";
|
|
2
2
|
import { getReferencesForSerializedEnumType, resolveTypeArgumentsInSerializedEnumType, } from "../types/EnumType.js";
|
|
3
3
|
export const isSerializedEnumDecl = (node) => node.kind === NodeKind.EnumDecl;
|
|
4
|
-
export const resolveTypeArgumentsInSerializedEnumDecl = (decls, args, decl) => {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
};
|
|
10
|
-
};
|
|
4
|
+
export const resolveTypeArgumentsInSerializedEnumDecl = (decls, args, decl) => ({
|
|
5
|
+
...decl,
|
|
6
|
+
parameters: [],
|
|
7
|
+
type: resolveTypeArgumentsInSerializedEnumType(decls, args, decl.type),
|
|
8
|
+
});
|
|
11
9
|
export const getReferencesForSerializedEnumDecl = (decls, decl, value) => getReferencesForSerializedEnumType(decls, decl.type, value);
|
|
12
10
|
export const ENUM_DISCRIMINATOR_KEY = "kind";
|
|
13
11
|
export const createEnumCaseValue = (caseName, caseValue) => ({
|
|
@@ -2,11 +2,11 @@ import { ENUM_DISCRIMINATOR_KEY } from "../declarations/EnumDecl.js";
|
|
|
2
2
|
import { getReferencesSerialized, resolveSerializedTypeArguments, } from "../Node.js";
|
|
3
3
|
export const resolveTypeArgumentsInSerializedEnumType = (decls, args, type) => ({
|
|
4
4
|
...type,
|
|
5
|
-
values: Object.fromEntries(Object.entries(type.values).map(([key, { type, ...caseMember }]) => [
|
|
5
|
+
values: Object.fromEntries(Object.entries(type.values).map(([key, { type: caseType, ...caseMember }]) => [
|
|
6
6
|
key,
|
|
7
7
|
{
|
|
8
8
|
...caseMember,
|
|
9
|
-
type:
|
|
9
|
+
type: caseType === null ? null : resolveSerializedTypeArguments(decls, args, caseType),
|
|
10
10
|
},
|
|
11
11
|
])),
|
|
12
12
|
});
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import type
|
|
2
|
-
import { type GetReferencesSerialized, type SerializedTypeArgumentsResolver } from "../Node.ts";
|
|
1
|
+
import { type NodeKind, type GetReferencesSerialized, type SerializedTypeArgumentsResolver } from "../Node.ts";
|
|
3
2
|
import { type SerializedIncludeIdentifierType } from "./IncludeIdentifierType.ts";
|
|
4
3
|
import { type SerializedMemberDecl, type SerializedObjectType } from "./ObjectType.ts";
|
|
5
4
|
import type { SerializedBaseType } from "./Type.ts";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { isNotEmpty } from "@elyukai/utils/array/nonEmpty";
|
|
2
2
|
import { error, isOk, ok, reduce } from "@elyukai/utils/result";
|
|
3
3
|
import { assertExhaustive, trySafe } from "@elyukai/utils/typeSafety";
|
|
4
|
-
const intPattern = /^(?:0|[1-9][0-9])
|
|
4
|
+
const intPattern = /^(?:0|[1-9][0-9])*$/u;
|
|
5
5
|
export const parseKeyPath = (keyPath) => normalizeKeyPath(keyPath).map(part => {
|
|
6
6
|
if (intPattern.test(part)) {
|
|
7
7
|
return { kind: "index", index: Number.parseInt(part, 10) };
|
|
@@ -26,8 +26,8 @@ export const renderParsedKeyPath = (keyPath) => keyPath
|
|
|
26
26
|
.join(".");
|
|
27
27
|
export const getAtKeyPath = (value, previousPath, remainingKeyPath, throwOnPathMismatch, fArray, fObject, ...fs) => {
|
|
28
28
|
if (isNotEmpty(remainingKeyPath)) {
|
|
29
|
-
const [
|
|
30
|
-
const getCaseAtKeyPath = (key, successFn) => reduce(successFn(key, value), newValue => getAtKeyPath(newValue, [...previousPath, key], remainingPath, throwOnPathMismatch, fArray, fObject, ...fs),
|
|
29
|
+
const [firstKey, ...remainingPath] = remainingKeyPath;
|
|
30
|
+
const getCaseAtKeyPath = (key, successFn) => reduce(successFn(key, value), newValue => getAtKeyPath(newValue, [...previousPath, key], remainingPath, throwOnPathMismatch, fArray, fObject, ...fs), err => {
|
|
31
31
|
for (const f of fs) {
|
|
32
32
|
const result = f(value, key);
|
|
33
33
|
if (isOk(result)) {
|
|
@@ -35,32 +35,32 @@ export const getAtKeyPath = (value, previousPath, remainingKeyPath, throwOnPathM
|
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
if (throwOnPathMismatch) {
|
|
38
|
-
throw new TypeError(
|
|
38
|
+
throw new TypeError(err(renderParsedKeyPath(previousPath)));
|
|
39
39
|
}
|
|
40
40
|
else {
|
|
41
41
|
return value;
|
|
42
42
|
}
|
|
43
43
|
});
|
|
44
|
-
switch (
|
|
44
|
+
switch (firstKey.kind) {
|
|
45
45
|
case "index":
|
|
46
|
-
return getCaseAtKeyPath(
|
|
46
|
+
return getCaseAtKeyPath(firstKey, (key, innerValue) => fArray(innerValue, key.index));
|
|
47
47
|
case "property":
|
|
48
|
-
return getCaseAtKeyPath(
|
|
48
|
+
return getCaseAtKeyPath(firstKey, (key, innerValue) => fObject(innerValue, key.name));
|
|
49
49
|
default:
|
|
50
|
-
return assertExhaustive(
|
|
50
|
+
return assertExhaustive(firstKey);
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
else {
|
|
54
54
|
return value;
|
|
55
55
|
}
|
|
56
56
|
};
|
|
57
|
-
export const getValueAtKeyPath = (value, keyPath, throwOnPathMismatch = false) => getAtKeyPath(value, [], parseKeyPath(keyPath), throwOnPathMismatch, (
|
|
58
|
-
? index >= 0 && index <
|
|
59
|
-
? ok(
|
|
57
|
+
export const getValueAtKeyPath = (value, keyPath, throwOnPathMismatch = false) => getAtKeyPath(value, [], parseKeyPath(keyPath), throwOnPathMismatch, (innerValue, index) => Array.isArray(innerValue)
|
|
58
|
+
? index >= 0 && index < innerValue.length
|
|
59
|
+
? ok(innerValue[index])
|
|
60
60
|
: error(previousPath => `Array at key path "${previousPath}" does not contain the index ${index.toString()}.`)
|
|
61
|
-
: error(previousPath => `Key path "${previousPath}" does not contain an array.`), (
|
|
62
|
-
? name in
|
|
63
|
-
? ok(
|
|
61
|
+
: error(previousPath => `Key path "${previousPath}" does not contain an array.`), (innerValue, name) => typeof innerValue === "object" && innerValue !== null
|
|
62
|
+
? name in innerValue
|
|
63
|
+
? ok(innerValue[name])
|
|
64
64
|
: error(previousPath => `Object at key path "${previousPath}" does not contain the key ${name}.`)
|
|
65
65
|
: error(previousPath => `Key path "${previousPath}" does not contain an object.`));
|
|
66
66
|
export const getValueAtKeyPathIfDefined = (value, keyPath) => trySafe(() => getValueAtKeyPath(value, keyPath, true));
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { assertExhaustive } from "@elyukai/utils/typeSafety";
|
|
1
2
|
export const isChangedInIndex = (fileStatus) => {
|
|
2
3
|
const { index } = fileStatus;
|
|
3
4
|
switch (index) {
|
|
@@ -14,6 +15,8 @@ export const isChangedInIndex = (fileStatus) => {
|
|
|
14
15
|
case "?":
|
|
15
16
|
case "!":
|
|
16
17
|
return false;
|
|
18
|
+
default:
|
|
19
|
+
return assertExhaustive(index);
|
|
17
20
|
}
|
|
18
21
|
};
|
|
19
22
|
export const isChangedInWorkingDir = (fileStatus) => {
|
|
@@ -32,6 +35,8 @@ export const isChangedInWorkingDir = (fileStatus) => {
|
|
|
32
35
|
case "m":
|
|
33
36
|
case "!":
|
|
34
37
|
return false;
|
|
38
|
+
default:
|
|
39
|
+
return assertExhaustive(workingDir);
|
|
35
40
|
}
|
|
36
41
|
};
|
|
37
42
|
const unchangedStatusCodes = new Set([" ", "!", "C", "T", "m", "U"]);
|
|
@@ -96,7 +101,7 @@ export const getLabelForGitStatus = (status) => {
|
|
|
96
101
|
return "";
|
|
97
102
|
}
|
|
98
103
|
};
|
|
99
|
-
const remotePattern = /^remotes\/(\w+?)\/(.+)
|
|
104
|
+
const remotePattern = /^remotes\/(\w+?)\/(.+)$/u;
|
|
100
105
|
export const splitBranchName = (branch) => {
|
|
101
106
|
const [_, remote, actualBranch] = branch.match(remotePattern) ?? ["", undefined, branch];
|
|
102
107
|
return { remote, name: actualBranch };
|
|
@@ -16,16 +16,16 @@ const mergeArraysByKey = (...arrayGroups) => arrayGroups.reduce((acc, arrayGroup
|
|
|
16
16
|
export const syntax = (strings, ...values) => strings.reduce((acc, str, i) => {
|
|
17
17
|
const nextValue = values[i];
|
|
18
18
|
if (typeof nextValue === "string") {
|
|
19
|
-
return [acc[0], acc[1] + str.replace(/\n/
|
|
19
|
+
return [acc[0], acc[1] + str.replace(/\n/gu, EOL) + nextValue];
|
|
20
20
|
}
|
|
21
21
|
else if (Array.isArray(nextValue)) {
|
|
22
22
|
return [
|
|
23
23
|
mergeArraysByKey(acc[0], nextValue[0]),
|
|
24
|
-
acc[1] + str.replace(/\n/
|
|
24
|
+
acc[1] + str.replace(/\n/gu, EOL) + nextValue[1],
|
|
25
25
|
];
|
|
26
26
|
}
|
|
27
27
|
else {
|
|
28
|
-
return [acc[0], acc[1] + str.replace(/\n/
|
|
28
|
+
return [acc[0], acc[1] + str.replace(/\n/gu, EOL)];
|
|
29
29
|
}
|
|
30
30
|
}, emptyRenderResult);
|
|
31
31
|
export const getIndentation = (spaces, indentLevel) => " ".repeat(spaces * indentLevel);
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { assertExhaustive } from "@elyukai/utils/typeSafety";
|
|
2
2
|
import { MessageError, parseMessage } from "messageformat";
|
|
3
|
-
const mergeAssoc = (acc, key, value) =>
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
};
|
|
3
|
+
const mergeAssoc = (acc, key, value) =>
|
|
4
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- if there is a previous value and the current result is null, keep the more specific one
|
|
5
|
+
({ ...acc, [key]: value ?? acc[key] });
|
|
7
6
|
const reduceMapAssoc = (map, acc, item) => {
|
|
8
7
|
const result = map(item);
|
|
9
8
|
if (result) {
|
|
@@ -26,26 +25,26 @@ const extractParameterFromDeclaration = (decl) => {
|
|
|
26
25
|
}
|
|
27
26
|
};
|
|
28
27
|
const extractParametersFromDeclarations = (decls) => decls.reduce((acc, decl) => reduceMapAssoc(extractParameterFromDeclaration, acc, decl), {});
|
|
29
|
-
const ignoreLocalVariables = (decls, acc) => decls.reduce((
|
|
30
|
-
local: (
|
|
31
|
-
const { [localDecl.name]: _, ...rest } =
|
|
28
|
+
const ignoreLocalVariables = (decls, acc) => decls.reduce((acc1, decl) => reduceADT({
|
|
29
|
+
local: (acc2, localDecl) => {
|
|
30
|
+
const { [localDecl.name]: _, ...rest } = acc2;
|
|
32
31
|
return rest;
|
|
33
32
|
},
|
|
34
|
-
},
|
|
35
|
-
const reduceParametersFromPattern = (acc, pattern) => pattern.reduce((
|
|
33
|
+
}, acc1, decl), acc);
|
|
34
|
+
const reduceParametersFromPattern = (acc, pattern) => pattern.reduce((acc1, element) => {
|
|
36
35
|
if (typeof element === "string") {
|
|
37
|
-
return
|
|
36
|
+
return acc1;
|
|
38
37
|
}
|
|
39
38
|
return reduceADT({
|
|
40
|
-
expression: (
|
|
41
|
-
if (!
|
|
42
|
-
return
|
|
39
|
+
expression: (acc2, element1) => {
|
|
40
|
+
if (!element1.arg) {
|
|
41
|
+
return acc2;
|
|
43
42
|
}
|
|
44
43
|
return reduceADT({
|
|
45
|
-
variable: (
|
|
46
|
-
},
|
|
44
|
+
variable: (acc3, variable) => mergeAssoc(acc3, variable.name, element1.functionRef?.name ?? null),
|
|
45
|
+
}, acc2, element1.arg);
|
|
47
46
|
},
|
|
48
|
-
},
|
|
47
|
+
}, acc1, element);
|
|
49
48
|
}, acc);
|
|
50
49
|
export const extractParameterTypeNamesFromMessage = (message) => {
|
|
51
50
|
try {
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { gte, lte } from "@elyukai/utils/equality";
|
|
2
2
|
export const parallelizeErrors = (errors) => errors.filter(error => error !== undefined);
|
|
3
|
-
const normalizeLabel = (label) => Array.isArray(label) ? label : [label, label
|
|
3
|
+
const normalizeLabel = (label) => Array.isArray(label) ? label : [label, `${label}s`];
|
|
4
4
|
export const validateLengthRangeBound = (end, label, rangeBound, value) => {
|
|
5
5
|
if (rangeBound === undefined) {
|
|
6
|
-
return;
|
|
6
|
+
return undefined;
|
|
7
7
|
}
|
|
8
8
|
const [operator, description] = end === "lower" ? [gte, "least"] : [lte, "most"];
|
|
9
|
-
const length = value
|
|
9
|
+
const { length } = value;
|
|
10
10
|
const normalizedLabel = normalizeLabel(label);
|
|
11
11
|
if (!operator(length, rangeBound)) {
|
|
12
12
|
return RangeError(`expected at ${description} ${rangeBound.toString()} ${normalizedLabel[rangeBound === 1 ? 0 : 1]}, but got ${length.toString()} ${normalizedLabel[length === 1 ? 0 : 1]}`);
|
|
13
13
|
}
|
|
14
|
-
return;
|
|
14
|
+
return undefined;
|
|
15
15
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { parallelizeErrors } from "../utils/validation.js";
|
|
2
|
-
const datePattern = /^\d{4}-\d{2}-\d{2}
|
|
3
|
-
const dateTimePattern = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}
|
|
2
|
+
const datePattern = /^\d{4}-\d{2}-\d{2}$/u;
|
|
3
|
+
const dateTimePattern = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/u;
|
|
4
4
|
const isValidISODateString = (dateString) => !isNaN(new Date(dateString).getTime());
|
|
5
5
|
export const validateDateConstraints = (constraints, value) => parallelizeErrors([
|
|
6
6
|
constraints.time === true
|
|
@@ -8,7 +8,7 @@ export const validateNumberConstraints = (constraints, value) => parallelizeErro
|
|
|
8
8
|
const normalizeRangeBound = (rangeBound) => typeof rangeBound === "number" ? { value: rangeBound, isExclusive: false } : rangeBound;
|
|
9
9
|
export const validateRangeBound = (end, rangeBound, value) => {
|
|
10
10
|
if (rangeBound === undefined) {
|
|
11
|
-
return;
|
|
11
|
+
return undefined;
|
|
12
12
|
}
|
|
13
13
|
const normalizedRangeBound = normalizeRangeBound(rangeBound);
|
|
14
14
|
const [operator, description] = end === "lower"
|
|
@@ -21,7 +21,7 @@ export const validateRangeBound = (end, rangeBound, value) => {
|
|
|
21
21
|
if (!operator(value, normalizedRangeBound.value)) {
|
|
22
22
|
return RangeError(`expected a value ${description} ${normalizedRangeBound.value.toString()}, but got ${value.toString()}`);
|
|
23
23
|
}
|
|
24
|
-
return;
|
|
24
|
+
return undefined;
|
|
25
25
|
};
|
|
26
26
|
export const validateMultipleOf = (multipleOf, value) => {
|
|
27
27
|
if (multipleOf === undefined) {
|
|
@@ -30,5 +30,5 @@ export const validateMultipleOf = (multipleOf, value) => {
|
|
|
30
30
|
if (value % multipleOf !== 0) {
|
|
31
31
|
return RangeError(`expected a value that is a multiple of ${multipleOf.toString()}, but got ${value.toString()}`);
|
|
32
32
|
}
|
|
33
|
-
return;
|
|
33
|
+
return undefined;
|
|
34
34
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { parallelizeErrors, validateLengthRangeBound } from "../utils/validation.js";
|
|
1
|
+
import { parallelizeErrors, validateLengthRangeBound, } from "../utils/validation.js";
|
|
2
2
|
export const validateObjectConstraints = (constraints, expectedKeys, value) => {
|
|
3
3
|
const actualKeys = Object.keys(value);
|
|
4
4
|
return parallelizeErrors([
|
|
@@ -13,7 +13,7 @@ export const validateStringConstraints = (constraints, value) => parallelizeErro
|
|
|
13
13
|
return undefined;
|
|
14
14
|
}
|
|
15
15
|
const pattern = typeof constraints.pattern === "string"
|
|
16
|
-
? new RegExp(constraints.pattern)
|
|
16
|
+
? new RegExp(constraints.pattern, "u")
|
|
17
17
|
: constraints.pattern;
|
|
18
18
|
return !pattern.test(value)
|
|
19
19
|
? TypeError(`string does not match the pattern ${pattern.toString()}`)
|