@valbuild/shared 0.125.0 → 0.127.0
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/CHANGELOG.md +250 -0
- package/dist/declarations/src/internal/ApiRoutes.d.ts +9 -1
- package/dist/declarations/src/internal/aiTools/aiSourceToolPatches.d.ts +2 -1
- package/dist/declarations/src/internal/emptyOf.d.ts +24 -1
- package/dist/declarations/src/internal/index.d.ts +1 -0
- package/dist/declarations/src/internal/localeAt.d.ts +19 -0
- package/dist/declarations/src/internal/resolveSchemaSourceFixes.d.ts +57 -8
- package/dist/declarations/src/internal/zod/SerializedSchema.d.ts +4 -2
- package/dist/declarations/src/internal/zod/ValDeployment.d.ts +1 -0
- package/internal/dist/valbuild-shared-internal.cjs.dev.js +636 -109
- package/internal/dist/valbuild-shared-internal.cjs.prod.js +636 -109
- package/internal/dist/valbuild-shared-internal.esm.js +629 -110
- package/package.json +2 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Internal, CODE_LANGUAGES, DEFAULT_COLOR_FORMAT } from '@valbuild/core';
|
|
1
|
+
import { Internal, CODE_LANGUAGES, resolveSettingsModule, missingDeclaredKeys, localeOfValue, discriminatedUnionBranchOf, DEFAULT_COLOR_FORMAT, declaredKeySetOf } from '@valbuild/core';
|
|
2
2
|
import { _ as _createForOfIteratorHelper, n as _objectSpread2, o as _arrayLikeToArray, q as _unsupportedIterableToArray, r as _defineProperty, s as _typeof } from '../../dist/getSitemapTree-a6cb37cb.esm.js';
|
|
3
3
|
export { b as VAL_AI_SESSION_STORAGE_KEY, d as VAL_CANVAS_MESSAGE, c as VAL_CANVAS_PARAM, V as VAL_CONFIG_SESSION_STORAGE_KEY, a as VAL_THEME_SESSION_STORAGE_KEY, g as getNextAppRouterSourceFolder, l as getPageRouterSitemapTree, j as getPageRouterSourceFolder, m as getPatternFromModuleFilePath, h as getTanStackRouterSourceFolder, k as isTanStackRoutesFolder, f as isValCanvasFrame, i as isValCanvasPageMessage, e as isValCanvasStudioMessage, p as parseRoutePattern, w as withValCanvasParam } from '../../dist/getSitemapTree-a6cb37cb.esm.js';
|
|
4
4
|
import { z } from 'zod';
|
|
@@ -982,19 +982,19 @@ var SerializedArraySchema = z.lazy(function () {
|
|
|
982
982
|
opt: z["boolean"]()
|
|
983
983
|
}));
|
|
984
984
|
});
|
|
985
|
-
var
|
|
986
|
-
return z.
|
|
987
|
-
type: z.literal("union"),
|
|
988
|
-
key: SerializedLiteralSchema,
|
|
989
|
-
items: z.array(SerializedLiteralSchema),
|
|
990
|
-
opt: z["boolean"]()
|
|
991
|
-
})), z.object(_objectSpread2(_objectSpread2({}, commonSchemaFields), {}, {
|
|
992
|
-
type: z.literal("union"),
|
|
985
|
+
var SerializedDiscriminatedUnionSchema = z.lazy(function () {
|
|
986
|
+
return z.object(_objectSpread2(_objectSpread2({}, commonSchemaFields), {}, {
|
|
987
|
+
type: z.literal("discriminated-union"),
|
|
993
988
|
key: z.string(),
|
|
994
989
|
items: z.array(SerializedObjectSchema),
|
|
995
990
|
opt: z["boolean"]()
|
|
996
|
-
}))
|
|
991
|
+
}));
|
|
997
992
|
});
|
|
993
|
+
var SerializedEnumSchema = z.object(_objectSpread2(_objectSpread2({}, commonSchemaFields), {}, {
|
|
994
|
+
type: z.literal("enum"),
|
|
995
|
+
values: z.array(z.string()),
|
|
996
|
+
opt: z["boolean"]()
|
|
997
|
+
}));
|
|
998
998
|
var ImageEncodeOption = z.union([z.literal(false), z.object({
|
|
999
999
|
type: z.literal("webp"),
|
|
1000
1000
|
quality: z.number().optional(),
|
|
@@ -1118,6 +1118,16 @@ var SerializedCodeSchema = z.object(_objectSpread2(_objectSpread2({}, commonSche
|
|
|
1118
1118
|
options: CodeOptions.optional(),
|
|
1119
1119
|
opt: z["boolean"]()
|
|
1120
1120
|
}));
|
|
1121
|
+
var SerializedLocaleSchema = z.object({
|
|
1122
|
+
type: z.literal("locale"),
|
|
1123
|
+
render: FieldRender,
|
|
1124
|
+
preview: z.literal(true).optional(),
|
|
1125
|
+
opt: z["boolean"](),
|
|
1126
|
+
customValidate: z["boolean"]().optional(),
|
|
1127
|
+
readonly: z["boolean"]().optional(),
|
|
1128
|
+
hidden: z["boolean"]().optional(),
|
|
1129
|
+
description: z.string().optional()
|
|
1130
|
+
});
|
|
1121
1131
|
var SerializedRouteSchema = z.object(_objectSpread2(_objectSpread2({}, commonSchemaFields), {}, {
|
|
1122
1132
|
type: z.literal("route"),
|
|
1123
1133
|
options: z.object({
|
|
@@ -1143,10 +1153,15 @@ var SerializedSettingsSchema = z.lazy(function () {
|
|
|
1143
1153
|
return z.object(_objectSpread2(_objectSpread2({}, commonSchemaFields), {}, {
|
|
1144
1154
|
type: z.literal("settings"),
|
|
1145
1155
|
items: z.record(z.string(), SerializedSchema),
|
|
1146
|
-
opt: z["boolean"]()
|
|
1156
|
+
opt: z["boolean"](),
|
|
1157
|
+
// Which section this is, where Val has rules about it beyond its keys.
|
|
1158
|
+
// Dropping it would leave the Studio's validation worker running every
|
|
1159
|
+
// field's own rules and none of the cross-field ones — see
|
|
1160
|
+
// `sectionValidators` in core/src/schema/settings.ts.
|
|
1161
|
+
section: z.string().optional()
|
|
1147
1162
|
}));
|
|
1148
1163
|
});
|
|
1149
|
-
var SerializedSchema = z.union([SerializedStringSchema, SerializedLiteralSchema, SerializedBooleanSchema, SerializedNumberSchema, SerializedObjectSchema, SerializedArraySchema,
|
|
1164
|
+
var SerializedSchema = z.union([SerializedStringSchema, SerializedLiteralSchema, SerializedBooleanSchema, SerializedNumberSchema, SerializedObjectSchema, SerializedArraySchema, SerializedDiscriminatedUnionSchema, SerializedEnumSchema, SerializedRichTextSchema, SerializedRecordSchema, SerializedKeyOfSchema, SerializedRouteSchema, SerializedLocaleSchema, SerializedFileSchema, SerializedDateSchema, SerializedDateTimeSchema, SerializedColorSchema, SerializedCodeSchema, SerializedSettingsSchema, SerializedImageSchema]);
|
|
1150
1165
|
|
|
1151
1166
|
var ValCommit = z.object({
|
|
1152
1167
|
commitSha: z.string(),
|
|
@@ -1158,6 +1173,31 @@ var ValCommit = z.object({
|
|
|
1158
1173
|
commitMessage: z.string().nullable()
|
|
1159
1174
|
});
|
|
1160
1175
|
|
|
1176
|
+
var ValDeployment = z.object({
|
|
1177
|
+
deploymentId: z.string(),
|
|
1178
|
+
deploymentState: z.string(),
|
|
1179
|
+
commitSha: z.string(),
|
|
1180
|
+
updatedAt: z.string(),
|
|
1181
|
+
createdAt: z.string(),
|
|
1182
|
+
/**
|
|
1183
|
+
* The commit message, as the deployment's host reported it.
|
|
1184
|
+
*
|
|
1185
|
+
* Val's OWN publishes carry their message on the commit (`ValCommit`), and
|
|
1186
|
+
* that is the one the Studio prefers — it is the message Val wrote. This is
|
|
1187
|
+
* for every OTHER deployment: a developer's push, a merged pull request, a
|
|
1188
|
+
* revert. Those have no Val commit at all, so without this the deploy feed
|
|
1189
|
+
* could only name them by their short sha, and "what went out at 14:02?" had
|
|
1190
|
+
* no answer inside the Studio.
|
|
1191
|
+
*
|
|
1192
|
+
* Optional AND nullable, and the two mean different things: absent is a
|
|
1193
|
+
* content service that does not report messages (or an older one), null is
|
|
1194
|
+
* one that reports having none. Both render as the short sha, so nothing
|
|
1195
|
+
* depends on telling them apart — but a schema that demanded the field would
|
|
1196
|
+
* reject the whole deployment feed of a service that does not send it.
|
|
1197
|
+
*/
|
|
1198
|
+
commitMessage: z.string().nullable().optional()
|
|
1199
|
+
});
|
|
1200
|
+
|
|
1161
1201
|
/**
|
|
1162
1202
|
* The wire shapes for reading history.
|
|
1163
1203
|
*
|
|
@@ -1297,7 +1337,7 @@ var ValConfig = z.object({
|
|
|
1297
1337
|
gitCommit: z.string().optional(),
|
|
1298
1338
|
gitBranch: z.string().optional()
|
|
1299
1339
|
});
|
|
1300
|
-
var ValidationFixZ = z.union([z.literal("image:add-metadata"), z.literal("image:check-metadata"), z.literal("image:check-remote"), z.literal("image:upload-remote"), z.literal("image:download-remote"), z.literal("images:check-remote"), z.literal("images:upload-remote"), z.literal("file:add-metadata"), z.literal("file:check-metadata"), z.literal("file:check-remote"), z.literal("file:upload-remote"), z.literal("file:download-remote"), z.literal("files:check-remote"), z.literal("files:upload-remote"), z.literal("keyof:check-keys"), z.literal("router:check-route"), z.literal("images:check-unique-folder"), z.literal("files:check-unique-folder"), z.literal("images:check-all-files"), z.literal("files:check-all-files"), z.literal("jsonValues:extract-entry")]);
|
|
1340
|
+
var ValidationFixZ = z.union([z.literal("image:add-metadata"), z.literal("image:check-metadata"), z.literal("image:check-remote"), z.literal("image:upload-remote"), z.literal("image:download-remote"), z.literal("images:check-remote"), z.literal("images:upload-remote"), z.literal("file:add-metadata"), z.literal("file:check-metadata"), z.literal("file:check-remote"), z.literal("file:upload-remote"), z.literal("file:download-remote"), z.literal("files:check-remote"), z.literal("files:upload-remote"), z.literal("keyof:check-keys"), z.literal("router:check-route"), z.literal("locale:check-locale"), z.literal("record:fill-keys"), z.literal("images:check-unique-folder"), z.literal("files:check-unique-folder"), z.literal("images:check-all-files"), z.literal("files:check-all-files"), z.literal("jsonValues:extract-entry")]);
|
|
1301
1341
|
var ValidationError = z.object({
|
|
1302
1342
|
message: z.string(),
|
|
1303
1343
|
value: z.unknown().optional(),
|
|
@@ -1750,6 +1790,21 @@ var Api = {
|
|
|
1750
1790
|
*/
|
|
1751
1791
|
headCommitSha: z.string().optional(),
|
|
1752
1792
|
commits: z.array(ValCommit),
|
|
1793
|
+
/**
|
|
1794
|
+
* The publishes the content service knows about.
|
|
1795
|
+
*
|
|
1796
|
+
* Declared, at last. `getStat` has always returned these in
|
|
1797
|
+
* `http` mode and the Studio has always read them - the response
|
|
1798
|
+
* validator strips unknown keys rather than rejecting them, and
|
|
1799
|
+
* the raw json is what the client hands back, so they arrived
|
|
1800
|
+
* while the contract said they could not. That was survivable
|
|
1801
|
+
* until a deployment started carrying a commit MESSAGE: a field
|
|
1802
|
+
* nobody has declared is a field the next person deletes.
|
|
1803
|
+
*
|
|
1804
|
+
* Optional, because a content service that reports no
|
|
1805
|
+
* deployments sends none.
|
|
1806
|
+
*/
|
|
1807
|
+
deployments: z.array(ValDeployment).optional(),
|
|
1753
1808
|
config: ValConfig,
|
|
1754
1809
|
profileId: z.string().nullable(),
|
|
1755
1810
|
mode: z.union([z.literal("http"), z.literal("fs")])
|
|
@@ -3189,7 +3244,7 @@ var compatible = {
|
|
|
3189
3244
|
* `readonly Json[]` — so the check that reads naturally does not type. This
|
|
3190
3245
|
* predicate is that check, said once.
|
|
3191
3246
|
*/
|
|
3192
|
-
function isJsonObject(value) {
|
|
3247
|
+
function isJsonObject$1(value) {
|
|
3193
3248
|
return _typeof(value) === "object" && value !== null && !Array.isArray(value);
|
|
3194
3249
|
}
|
|
3195
3250
|
function incompatible(reason) {
|
|
@@ -3242,21 +3297,11 @@ function explainIncompatible(reason) {
|
|
|
3242
3297
|
* not a failure: it is what makes the caller return `unknown` rather than guess.
|
|
3243
3298
|
*/
|
|
3244
3299
|
function variantOf(schema, value) {
|
|
3245
|
-
if (schema.type !== "union") {
|
|
3300
|
+
if (schema.type !== "discriminated-union") {
|
|
3246
3301
|
return undefined;
|
|
3247
3302
|
}
|
|
3248
|
-
// String union: the value IS the discriminator.
|
|
3249
|
-
if (typeof schema.key !== "string") {
|
|
3250
|
-
if (typeof value !== "string") {
|
|
3251
|
-
return undefined;
|
|
3252
|
-
}
|
|
3253
|
-
return schema.items.find(function (item) {
|
|
3254
|
-
return item.type === "literal" && item.value === value;
|
|
3255
|
-
});
|
|
3256
|
-
}
|
|
3257
|
-
// Object union: the discriminator is a literal at `key`.
|
|
3258
3303
|
var discriminator = schema.key;
|
|
3259
|
-
if (!isJsonObject(value)) {
|
|
3304
|
+
if (!isJsonObject$1(value)) {
|
|
3260
3305
|
return undefined;
|
|
3261
3306
|
}
|
|
3262
3307
|
var tag = value[discriminator];
|
|
@@ -3272,9 +3317,6 @@ function variantOf(schema, value) {
|
|
|
3272
3317
|
});
|
|
3273
3318
|
}
|
|
3274
3319
|
function describeVariant(schema, key) {
|
|
3275
|
-
if (schema.type === "literal") {
|
|
3276
|
-
return schema.value;
|
|
3277
|
-
}
|
|
3278
3320
|
if (schema.type === "object") {
|
|
3279
3321
|
var tag = schema.items[key];
|
|
3280
3322
|
if ((tag === null || tag === void 0 ? void 0 : tag.type) === "literal") {
|
|
@@ -3292,11 +3334,24 @@ function checkCompatibility(from, to) {
|
|
|
3292
3334
|
});
|
|
3293
3335
|
}
|
|
3294
3336
|
|
|
3337
|
+
// An enum's domain IS its schema, so the value decides: whatever the old
|
|
3338
|
+
// schema was — an enum, a literal, a plain string — the only question is
|
|
3339
|
+
// whether this string is still offered here.
|
|
3340
|
+
if (to.schema.type === "enum") {
|
|
3341
|
+
if (typeof from.value === "string" && to.schema.values.includes(from.value)) {
|
|
3342
|
+
return compatible;
|
|
3343
|
+
}
|
|
3344
|
+
return incompatible({
|
|
3345
|
+
kind: "no-matching-variant",
|
|
3346
|
+
variants: to.schema.values
|
|
3347
|
+
});
|
|
3348
|
+
}
|
|
3349
|
+
|
|
3295
3350
|
// A changed union is not itself disqualifying. What matters is whether the
|
|
3296
3351
|
// variant being restored still has somewhere to go — comparing the unions
|
|
3297
3352
|
// wholesale would refuse a restore that is perfectly safe.
|
|
3298
|
-
if (to.schema.type === "union") {
|
|
3299
|
-
var key =
|
|
3353
|
+
if (to.schema.type === "discriminated-union") {
|
|
3354
|
+
var key = to.schema.key;
|
|
3300
3355
|
var _iterator = _createForOfIteratorHelper(to.schema.items),
|
|
3301
3356
|
_step;
|
|
3302
3357
|
try {
|
|
@@ -3321,9 +3376,9 @@ function checkCompatibility(from, to) {
|
|
|
3321
3376
|
});
|
|
3322
3377
|
}
|
|
3323
3378
|
|
|
3324
|
-
// Coming FROM a union into something that is not one: only the
|
|
3325
|
-
// value actually is matters, so narrow before comparing.
|
|
3326
|
-
if (from.schema.type === "union") {
|
|
3379
|
+
// Coming FROM a discriminated union into something that is not one: only the
|
|
3380
|
+
// variant this value actually is matters, so narrow before comparing.
|
|
3381
|
+
if (from.schema.type === "discriminated-union") {
|
|
3327
3382
|
var _variant = variantOf(from.schema, from.value);
|
|
3328
3383
|
if (_variant === undefined) {
|
|
3329
3384
|
return {
|
|
@@ -3336,6 +3391,25 @@ function checkCompatibility(from, to) {
|
|
|
3336
3391
|
value: from.value
|
|
3337
3392
|
}, to);
|
|
3338
3393
|
}
|
|
3394
|
+
|
|
3395
|
+
// Coming FROM an enum into something that is not one: the value it holds is
|
|
3396
|
+
// all the old schema contributes, so compare as that one value.
|
|
3397
|
+
if (from.schema.type === "enum") {
|
|
3398
|
+
if (typeof from.value !== "string") {
|
|
3399
|
+
return {
|
|
3400
|
+
status: "unknown",
|
|
3401
|
+
message: "The old value is not one of the options it was stored as, so we cannot tell whether it fits here."
|
|
3402
|
+
};
|
|
3403
|
+
}
|
|
3404
|
+
return checkCompatibility({
|
|
3405
|
+
schema: {
|
|
3406
|
+
type: "literal",
|
|
3407
|
+
value: from.value,
|
|
3408
|
+
opt: from.schema.opt
|
|
3409
|
+
},
|
|
3410
|
+
value: from.value
|
|
3411
|
+
}, to);
|
|
3412
|
+
}
|
|
3339
3413
|
if (from.schema.type !== to.schema.type) {
|
|
3340
3414
|
return incompatible({
|
|
3341
3415
|
kind: "type-changed",
|
|
@@ -3355,7 +3429,7 @@ function checkCompatibility(from, to) {
|
|
|
3355
3429
|
}
|
|
3356
3430
|
case "object":
|
|
3357
3431
|
{
|
|
3358
|
-
if (from.schema.type !== "object" || !isJsonObject(from.value)) {
|
|
3432
|
+
if (from.schema.type !== "object" || !isJsonObject$1(from.value)) {
|
|
3359
3433
|
return {
|
|
3360
3434
|
status: "unknown",
|
|
3361
3435
|
message: "The old value is not shaped like an object."
|
|
@@ -3458,7 +3532,7 @@ function checkCompatibility(from, to) {
|
|
|
3458
3532
|
}
|
|
3459
3533
|
case "record":
|
|
3460
3534
|
{
|
|
3461
|
-
if (from.schema.type !== "record" || !isJsonObject(from.value)) {
|
|
3535
|
+
if (from.schema.type !== "record" || !isJsonObject$1(from.value)) {
|
|
3462
3536
|
return {
|
|
3463
3537
|
status: "unknown",
|
|
3464
3538
|
message: "The old value is not a record."
|
|
@@ -3569,14 +3643,6 @@ var SharedValConfig = z.object({
|
|
|
3569
3643
|
* Config that is shared between the client and server.
|
|
3570
3644
|
*/
|
|
3571
3645
|
|
|
3572
|
-
var ValDeployment = z.object({
|
|
3573
|
-
deploymentId: z.string(),
|
|
3574
|
-
deploymentState: z.string(),
|
|
3575
|
-
commitSha: z.string(),
|
|
3576
|
-
updatedAt: z.string(),
|
|
3577
|
-
createdAt: z.string()
|
|
3578
|
-
});
|
|
3579
|
-
|
|
3580
3646
|
/**
|
|
3581
3647
|
* Shared route validation utilities
|
|
3582
3648
|
*/
|
|
@@ -3749,6 +3815,16 @@ function findSimilar(key, targets) {
|
|
|
3749
3815
|
return a.distance - b.distance;
|
|
3750
3816
|
});
|
|
3751
3817
|
}
|
|
3818
|
+
/**
|
|
3819
|
+
* The record a `keyof:check-keys` error resolves against — the value and the
|
|
3820
|
+
* schema at the error's `sourcePath`.
|
|
3821
|
+
*
|
|
3822
|
+
* Exported for the one consumer that has to know what a resolution DEPENDED
|
|
3823
|
+
* on rather than what it concluded: `ValidationStore` re-reads the keys here
|
|
3824
|
+
* to decide whether a change to the referenced module can have moved the
|
|
3825
|
+
* answer. Keep this and {@link checkKeyIsValid} reading the same record, or the
|
|
3826
|
+
* store will invalidate on one record and the resolution answer from another.
|
|
3827
|
+
*/
|
|
3752
3828
|
function getKeyOfRecordAt(sourcePath, snapshot) {
|
|
3753
3829
|
var _Internal$splitModule = Internal.splitModuleFilePathAndModulePath(sourcePath),
|
|
3754
3830
|
_Internal$splitModule2 = _slicedToArray(_Internal$splitModule, 2),
|
|
@@ -3892,16 +3968,92 @@ function checkRouteIsValid(route, includePattern, excludePattern, snapshot) {
|
|
|
3892
3968
|
error: false
|
|
3893
3969
|
};
|
|
3894
3970
|
}
|
|
3971
|
+
|
|
3972
|
+
/**
|
|
3973
|
+
* The languages the project declares, from its settings module.
|
|
3974
|
+
*
|
|
3975
|
+
* Empty where there is no settings module, no `locales` section, or nothing in
|
|
3976
|
+
* it — all of which mean the same thing: this project has not said it is
|
|
3977
|
+
* translated.
|
|
3978
|
+
*/
|
|
3979
|
+
function declaredLocales(snapshot) {
|
|
3980
|
+
var _resolveSettingsModul = resolveSettingsModule(snapshot.schemas),
|
|
3981
|
+
moduleFilePath = _resolveSettingsModul.moduleFilePath;
|
|
3982
|
+
if (moduleFilePath === null) {
|
|
3983
|
+
return [];
|
|
3984
|
+
}
|
|
3985
|
+
var source = snapshot.sources[moduleFilePath];
|
|
3986
|
+
if (_typeof(source) !== "object" || source === null || Array.isArray(source)) {
|
|
3987
|
+
return [];
|
|
3988
|
+
}
|
|
3989
|
+
var locales = source["locales"];
|
|
3990
|
+
if (_typeof(locales) !== "object" || locales === null || Array.isArray(locales)) {
|
|
3991
|
+
return [];
|
|
3992
|
+
}
|
|
3993
|
+
var available = locales["available"];
|
|
3994
|
+
if (!Array.isArray(available)) {
|
|
3995
|
+
return [];
|
|
3996
|
+
}
|
|
3997
|
+
return available.filter(function (tag) {
|
|
3998
|
+
return typeof tag === "string";
|
|
3999
|
+
});
|
|
4000
|
+
}
|
|
4001
|
+
/**
|
|
4002
|
+
* The fixes {@link resolveSchemaSourceFixForError} answers for.
|
|
4003
|
+
*
|
|
4004
|
+
* A marker error carrying one of these is NOT a message: it says "ask the whole
|
|
4005
|
+
* project about this" and carries the value to ask with, because the schema
|
|
4006
|
+
* that raised it can only see its own module. Left unresolved, what a user sees
|
|
4007
|
+
* is the marker's own placeholder text — "should typically be processed by Val
|
|
4008
|
+
* internally … version mismatch" — which is alarming and says nothing.
|
|
4009
|
+
*
|
|
4010
|
+
* A list rather than a check per call site: every caller that resolves some of
|
|
4011
|
+
* these has to resolve all of them, and the two that leaked did so by adding a
|
|
4012
|
+
* fix here and not to a condition somewhere else.
|
|
4013
|
+
*/
|
|
4014
|
+
var SCHEMA_SOURCE_FIXES = ["keyof:check-keys", "router:check-route", "locale:check-locale", "record:fill-keys"];
|
|
4015
|
+
|
|
4016
|
+
/** Whether an error is a marker only the whole project can answer. */
|
|
4017
|
+
function isSchemaSourceFixError(error) {
|
|
4018
|
+
var _error$fixes;
|
|
4019
|
+
return ((_error$fixes = error.fixes) !== null && _error$fixes !== void 0 ? _error$fixes : []).some(function (fix) {
|
|
4020
|
+
return SCHEMA_SOURCE_FIXES.includes(fix);
|
|
4021
|
+
});
|
|
4022
|
+
}
|
|
4023
|
+
|
|
3895
4024
|
/**
|
|
3896
|
-
*
|
|
3897
|
-
*
|
|
4025
|
+
* The record a `keyof:check-keys` error resolves against, or null for any other
|
|
4026
|
+
* error — including a malformed marker, which
|
|
4027
|
+
* {@link resolveSchemaSourceFixForError} reports and this has nothing to say
|
|
4028
|
+
* about.
|
|
4029
|
+
*
|
|
4030
|
+
* For a consumer that needs to know what the resolution READS, not what it
|
|
4031
|
+
* concludes: `ValidationStore` keeps this per validated module, so that a change
|
|
4032
|
+
* to the referenced record can invalidate the module holding the reference.
|
|
4033
|
+
*/
|
|
4034
|
+
function keyOfRecordPath(error) {
|
|
4035
|
+
var _error$fixes2;
|
|
4036
|
+
if (!((_error$fixes2 = error.fixes) !== null && _error$fixes2 !== void 0 ? _error$fixes2 : []).includes("keyof:check-keys")) {
|
|
4037
|
+
return null;
|
|
4038
|
+
}
|
|
4039
|
+
var value = error.value;
|
|
4040
|
+
if (!value || _typeof(value) !== "object") {
|
|
4041
|
+
return null;
|
|
4042
|
+
}
|
|
4043
|
+
var sourcePath = value.sourcePath;
|
|
4044
|
+
return typeof sourcePath === "string" ? sourcePath : null;
|
|
4045
|
+
}
|
|
4046
|
+
|
|
4047
|
+
/**
|
|
4048
|
+
* Resolves a single marker error (see {@link SCHEMA_SOURCE_FIXES}) against the
|
|
4049
|
+
* given schema/source snapshot. Returns:
|
|
3898
4050
|
* - null if the error is not one of these fixes (caller should pass through)
|
|
3899
|
-
* - { status: "resolved" } if the
|
|
4051
|
+
* - { status: "resolved" } if the reference is valid (drop error)
|
|
3900
4052
|
* - { status: "remaining"; error } if invalid (rewritten error to surface)
|
|
3901
4053
|
*/
|
|
3902
4054
|
function resolveSchemaSourceFixForError(error, snapshot) {
|
|
3903
|
-
var _error$
|
|
3904
|
-
var fixes = (_error$
|
|
4055
|
+
var _error$fixes3;
|
|
4056
|
+
var fixes = (_error$fixes3 = error.fixes) !== null && _error$fixes3 !== void 0 ? _error$fixes3 : [];
|
|
3905
4057
|
if (fixes.includes("keyof:check-keys")) {
|
|
3906
4058
|
if (!error.value) {
|
|
3907
4059
|
return {
|
|
@@ -3960,6 +4112,120 @@ function resolveSchemaSourceFixForError(error, snapshot) {
|
|
|
3960
4112
|
status: "resolved"
|
|
3961
4113
|
};
|
|
3962
4114
|
}
|
|
4115
|
+
if (fixes.includes("locale:check-locale")) {
|
|
4116
|
+
var value = error.value;
|
|
4117
|
+
if (_typeof(value) !== "object" || value === null) {
|
|
4118
|
+
return {
|
|
4119
|
+
status: "remaining",
|
|
4120
|
+
error: _objectSpread2(_objectSpread2({}, error), {}, {
|
|
4121
|
+
message: "Expected locale validation error to have a 'value' object. Found: ".concat(_typeof(value), ". ").concat(TYPE_ERROR_MESSAGE),
|
|
4122
|
+
typeError: true,
|
|
4123
|
+
fixes: undefined
|
|
4124
|
+
})
|
|
4125
|
+
};
|
|
4126
|
+
}
|
|
4127
|
+
var _ref6 = value,
|
|
4128
|
+
locale = _ref6.locale;
|
|
4129
|
+
if (typeof locale !== "string") {
|
|
4130
|
+
return {
|
|
4131
|
+
status: "remaining",
|
|
4132
|
+
error: _objectSpread2(_objectSpread2({}, error), {}, {
|
|
4133
|
+
message: "Expected locale validation error 'value' to have property 'locale' of type 'string'. Found: ".concat(_typeof(locale), ". ").concat(TYPE_ERROR_MESSAGE),
|
|
4134
|
+
typeError: true,
|
|
4135
|
+
fixes: undefined
|
|
4136
|
+
})
|
|
4137
|
+
};
|
|
4138
|
+
}
|
|
4139
|
+
var available = declaredLocales(snapshot);
|
|
4140
|
+
if (available.length === 0) {
|
|
4141
|
+
return {
|
|
4142
|
+
status: "remaining",
|
|
4143
|
+
error: _objectSpread2(_objectSpread2({}, error), {}, {
|
|
4144
|
+
// The project has not said it is translated, so the value is not
|
|
4145
|
+
// wrong so much as premature — and the fix is in another file.
|
|
4146
|
+
message: "This project has no languages. Declare them under 'locales.available' in the settings module before using s.locale().",
|
|
4147
|
+
fixes: undefined
|
|
4148
|
+
})
|
|
4149
|
+
};
|
|
4150
|
+
}
|
|
4151
|
+
if (available.includes(locale)) {
|
|
4152
|
+
return {
|
|
4153
|
+
status: "resolved"
|
|
4154
|
+
};
|
|
4155
|
+
}
|
|
4156
|
+
return {
|
|
4157
|
+
status: "remaining",
|
|
4158
|
+
error: _objectSpread2(_objectSpread2({}, error), {}, {
|
|
4159
|
+
message: "'".concat(locale, "' is not one of this project's languages: ").concat(available.map(function (each) {
|
|
4160
|
+
return "'".concat(each, "'");
|
|
4161
|
+
}).join(", ")),
|
|
4162
|
+
fixes: undefined
|
|
4163
|
+
})
|
|
4164
|
+
};
|
|
4165
|
+
}
|
|
4166
|
+
if (fixes.includes("record:fill-keys")) {
|
|
4167
|
+
var _value = error.value;
|
|
4168
|
+
if (_typeof(_value) !== "object" || _value === null) {
|
|
4169
|
+
return {
|
|
4170
|
+
status: "remaining",
|
|
4171
|
+
error: _objectSpread2(_objectSpread2({}, error), {}, {
|
|
4172
|
+
message: "Expected record key validation error to have a 'value' object. Found: ".concat(_typeof(_value), ". ").concat(TYPE_ERROR_MESSAGE),
|
|
4173
|
+
typeError: true,
|
|
4174
|
+
fixes: undefined
|
|
4175
|
+
})
|
|
4176
|
+
};
|
|
4177
|
+
}
|
|
4178
|
+
var _ref7 = _value,
|
|
4179
|
+
present = _ref7.present,
|
|
4180
|
+
declared = _ref7.declared;
|
|
4181
|
+
if (!Array.isArray(present)) {
|
|
4182
|
+
return {
|
|
4183
|
+
status: "remaining",
|
|
4184
|
+
error: _objectSpread2(_objectSpread2({}, error), {}, {
|
|
4185
|
+
message: "Expected record key validation error 'value' to have property 'present' of type 'array'. Found: ".concat(_typeof(present), ". ").concat(TYPE_ERROR_MESSAGE),
|
|
4186
|
+
typeError: true,
|
|
4187
|
+
fixes: undefined
|
|
4188
|
+
})
|
|
4189
|
+
};
|
|
4190
|
+
}
|
|
4191
|
+
var presentKeys = present.filter(function (key) {
|
|
4192
|
+
return typeof key === "string";
|
|
4193
|
+
});
|
|
4194
|
+
// A literal union brought its keys along; a locale record left them to be
|
|
4195
|
+
// read out of the settings module, which is the whole reason this check is
|
|
4196
|
+
// resolved here rather than in the schema.
|
|
4197
|
+
var declaredKeys = Array.isArray(declared) ? declared.filter(function (key) {
|
|
4198
|
+
return typeof key === "string";
|
|
4199
|
+
}) : declaredLocales(snapshot);
|
|
4200
|
+
if (declaredKeys.length === 0) {
|
|
4201
|
+
// A locale record on a project that has declared no languages. There is
|
|
4202
|
+
// nothing to require, and the locale field's own check already says the
|
|
4203
|
+
// project has not declared any — saying it twice on one record would not
|
|
4204
|
+
// add anything.
|
|
4205
|
+
return {
|
|
4206
|
+
status: "resolved"
|
|
4207
|
+
};
|
|
4208
|
+
}
|
|
4209
|
+
var missing = missingDeclaredKeys(declaredKeys, presentKeys);
|
|
4210
|
+
if (missing.length === 0) {
|
|
4211
|
+
return {
|
|
4212
|
+
status: "resolved"
|
|
4213
|
+
};
|
|
4214
|
+
}
|
|
4215
|
+
return {
|
|
4216
|
+
status: "remaining",
|
|
4217
|
+
error: _objectSpread2(_objectSpread2({}, error), {}, {
|
|
4218
|
+
message: "Missing ".concat(missing.length === 1 ? "key" : "keys", ": ").concat(missing.map(function (each) {
|
|
4219
|
+
return "'".concat(each, "'");
|
|
4220
|
+
}).join(", "), ". This record's keys are declared by its schema, so every one of them is an entry \u2014 an entry nobody has written yet is null, not absent."),
|
|
4221
|
+
value: {
|
|
4222
|
+
missing: missing,
|
|
4223
|
+
declared: declaredKeys
|
|
4224
|
+
},
|
|
4225
|
+
fixes: undefined
|
|
4226
|
+
})
|
|
4227
|
+
};
|
|
4228
|
+
}
|
|
3963
4229
|
if (fixes.includes("router:check-route")) {
|
|
3964
4230
|
if (!error.value) {
|
|
3965
4231
|
return {
|
|
@@ -4021,10 +4287,10 @@ function asRegExpPattern(value) {
|
|
|
4021
4287
|
/**
|
|
4022
4288
|
* Apply schema/source fix resolution across a map of validation errors.
|
|
4023
4289
|
*
|
|
4024
|
-
* Errors
|
|
4025
|
-
*
|
|
4026
|
-
*
|
|
4027
|
-
*
|
|
4290
|
+
* Errors carrying one of {@link SCHEMA_SOURCE_FIXES} are resolved against the
|
|
4291
|
+
* in-memory schema/source snapshot — valid references drop the error, invalid
|
|
4292
|
+
* ones are rewritten with a "did you mean…" message and have their `fixes`
|
|
4293
|
+
* cleared (so downstream code reports them as plain validation errors).
|
|
4028
4294
|
* All other errors pass through untouched.
|
|
4029
4295
|
*
|
|
4030
4296
|
* Source paths with no remaining errors are removed from the result.
|
|
@@ -4058,6 +4324,189 @@ function resolveSchemaSourceFixes(validationErrors, snapshot) {
|
|
|
4058
4324
|
return result;
|
|
4059
4325
|
}
|
|
4060
4326
|
|
|
4327
|
+
/**
|
|
4328
|
+
* Which of the project's languages governs a path, or `null` for none.
|
|
4329
|
+
*
|
|
4330
|
+
* THE question the whole feature turns on. A locale scope is a subtree in one
|
|
4331
|
+
* language, and three things open one: a `locale` field on an object, a record
|
|
4332
|
+
* keyed by `s.locale()`, and a locale segment in a segmented key. Once this can
|
|
4333
|
+
* be answered from the schema and the source alone, everything downstream falls
|
|
4334
|
+
* out of it — the Studio's locale filter, deep links, `<html lang>`, and knowing
|
|
4335
|
+
* what to translate from and into.
|
|
4336
|
+
*
|
|
4337
|
+
* One implementation, so the Studio, the server and the validation worker cannot
|
|
4338
|
+
* disagree about what language a piece of content is in.
|
|
4339
|
+
*
|
|
4340
|
+
* `null` means no scope governs the path — which is the answer for most content
|
|
4341
|
+
* in most projects, and for every project that has not declared any languages.
|
|
4342
|
+
*/
|
|
4343
|
+
function localeAt(path, snapshot) {
|
|
4344
|
+
var available = declaredLocales(snapshot);
|
|
4345
|
+
if (available.length === 0) {
|
|
4346
|
+
// Nothing can be one of no languages. Answering `null` rather than reading
|
|
4347
|
+
// the content is also what makes this cheap for the projects that are not
|
|
4348
|
+
// translated at all.
|
|
4349
|
+
return null;
|
|
4350
|
+
}
|
|
4351
|
+
var _Internal$splitModule = Internal.splitModuleFilePathAndModulePath(path),
|
|
4352
|
+
_Internal$splitModule2 = _slicedToArray(_Internal$splitModule, 2),
|
|
4353
|
+
moduleFilePath = _Internal$splitModule2[0],
|
|
4354
|
+
modulePath = _Internal$splitModule2[1];
|
|
4355
|
+
var schema = snapshot.schemas[moduleFilePath];
|
|
4356
|
+
var source = snapshot.sources[moduleFilePath];
|
|
4357
|
+
if (schema === undefined || source === undefined) {
|
|
4358
|
+
return null;
|
|
4359
|
+
}
|
|
4360
|
+
var segments = modulePath ? Internal.splitModulePath(modulePath) : [];
|
|
4361
|
+
return walk(schema, source, segments, available);
|
|
4362
|
+
}
|
|
4363
|
+
|
|
4364
|
+
/**
|
|
4365
|
+
* Walk from a node towards `segments`, answering with the innermost scope.
|
|
4366
|
+
*
|
|
4367
|
+
* The scope is read on ARRIVAL at each node — the node the path names included,
|
|
4368
|
+
* not only the ones passed through on the way to it. So `localeAt` of a
|
|
4369
|
+
* scope-opening object is that object's own locale rather than its parent's,
|
|
4370
|
+
* and a path that stops AT a block still answers with the block's language.
|
|
4371
|
+
*
|
|
4372
|
+
* A scope may not contain another (see `localeScopeErrors`), so at most one of
|
|
4373
|
+
* these can fire on a well-formed path; taking the innermost is what makes the
|
|
4374
|
+
* answer well-defined while a project is mid-fix.
|
|
4375
|
+
*/
|
|
4376
|
+
function walk(schema, source, segments, available) {
|
|
4377
|
+
var entered = enter(schema, source, available);
|
|
4378
|
+
var locale = entered.locale;
|
|
4379
|
+
var currentSchema = entered.schema;
|
|
4380
|
+
var currentSource = source;
|
|
4381
|
+
var _iterator = _createForOfIteratorHelper(segments),
|
|
4382
|
+
_step;
|
|
4383
|
+
try {
|
|
4384
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
4385
|
+
var segment = _step.value;
|
|
4386
|
+
if (currentSchema === undefined) {
|
|
4387
|
+
return locale;
|
|
4388
|
+
}
|
|
4389
|
+
if (currentSchema.type === "record") {
|
|
4390
|
+
var _currentSchema$key;
|
|
4391
|
+
if (((_currentSchema$key = currentSchema.key) === null || _currentSchema$key === void 0 ? void 0 : _currentSchema$key.type) === "locale") {
|
|
4392
|
+
// In a locale-keyed record the KEY is the language, so the segment we
|
|
4393
|
+
// are about to take is the answer.
|
|
4394
|
+
var resolved = localeOfValue(segment, available);
|
|
4395
|
+
if (resolved !== null) {
|
|
4396
|
+
locale = resolved;
|
|
4397
|
+
}
|
|
4398
|
+
}
|
|
4399
|
+
currentSchema = currentSchema.item;
|
|
4400
|
+
} else if (currentSchema.type === "array") {
|
|
4401
|
+
currentSchema = currentSchema.item;
|
|
4402
|
+
} else if (currentSchema.type === "object" || currentSchema.type === "settings") {
|
|
4403
|
+
currentSchema = currentSchema.items[segment];
|
|
4404
|
+
} else {
|
|
4405
|
+
// A leaf, or richtext's internal structure. Nothing below opens a scope.
|
|
4406
|
+
return locale;
|
|
4407
|
+
}
|
|
4408
|
+
currentSource = childSource(currentSource, segment);
|
|
4409
|
+
entered = enter(currentSchema, currentSource, available);
|
|
4410
|
+
currentSchema = entered.schema;
|
|
4411
|
+
if (entered.locale !== null) {
|
|
4412
|
+
locale = entered.locale;
|
|
4413
|
+
}
|
|
4414
|
+
}
|
|
4415
|
+
} catch (err) {
|
|
4416
|
+
_iterator.e(err);
|
|
4417
|
+
} finally {
|
|
4418
|
+
_iterator.f();
|
|
4419
|
+
}
|
|
4420
|
+
return locale;
|
|
4421
|
+
}
|
|
4422
|
+
|
|
4423
|
+
/**
|
|
4424
|
+
* Arrive at a node: resolve what it really is, and read the scope it opens.
|
|
4425
|
+
*
|
|
4426
|
+
* A discriminated union is a fork rather than a level — the variant the value
|
|
4427
|
+
* takes IS the node — so it is resolved here, before anything asks what the
|
|
4428
|
+
* node holds. Doing that on arrival rather than on the way down is the
|
|
4429
|
+
* difference between a block's own path answering with its language and
|
|
4430
|
+
* answering with nothing.
|
|
4431
|
+
*/
|
|
4432
|
+
function enter(schema, source, available) {
|
|
4433
|
+
var resolved = (schema === null || schema === void 0 ? void 0 : schema.type) === "discriminated-union" ? variantOfUnion(schema, source) : schema;
|
|
4434
|
+
return {
|
|
4435
|
+
schema: resolved,
|
|
4436
|
+
locale: resolved === undefined ? null : localeOfObjectField(resolved, source, available)
|
|
4437
|
+
};
|
|
4438
|
+
}
|
|
4439
|
+
|
|
4440
|
+
/**
|
|
4441
|
+
* The language an object's own `locale` field says it is in, if it has one.
|
|
4442
|
+
*
|
|
4443
|
+
* Reads the SOURCE, since unlike a record key the value is content rather than
|
|
4444
|
+
* part of the path. A field that has not been filled in, or holds something
|
|
4445
|
+
* that is not one of the project's languages, is not an answer — validation is
|
|
4446
|
+
* already reporting that, and guessing here would put a language in
|
|
4447
|
+
* `<html lang>` that nobody chose.
|
|
4448
|
+
*/
|
|
4449
|
+
function localeOfObjectField(schema, source, available) {
|
|
4450
|
+
if (schema.type !== "object" || !isJsonObject(source)) {
|
|
4451
|
+
return null;
|
|
4452
|
+
}
|
|
4453
|
+
for (var _i = 0, _Object$entries = Object.entries(schema.items); _i < _Object$entries.length; _i++) {
|
|
4454
|
+
var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
|
|
4455
|
+
key = _Object$entries$_i[0],
|
|
4456
|
+
item = _Object$entries$_i[1];
|
|
4457
|
+
if (item.type !== "locale") {
|
|
4458
|
+
continue;
|
|
4459
|
+
}
|
|
4460
|
+
var value = source[key];
|
|
4461
|
+
if (typeof value !== "string") {
|
|
4462
|
+
return null;
|
|
4463
|
+
}
|
|
4464
|
+
return localeOfValue(value, available);
|
|
4465
|
+
}
|
|
4466
|
+
return null;
|
|
4467
|
+
}
|
|
4468
|
+
|
|
4469
|
+
/**
|
|
4470
|
+
* The variant a value takes, or `undefined` if the tag matches none.
|
|
4471
|
+
*
|
|
4472
|
+
* The tag is read off the source here; picking the variant is
|
|
4473
|
+
* {@link discriminatedUnionBranchOf}, shared with the Studio's locale filter so
|
|
4474
|
+
* the two cannot disagree about which variant a row is. `s.enum()` never
|
|
4475
|
+
* reaches this — it is a leaf, with nothing under it to walk into.
|
|
4476
|
+
*/
|
|
4477
|
+
function variantOfUnion(schema, source) {
|
|
4478
|
+
if (!isJsonObject(source)) {
|
|
4479
|
+
return undefined;
|
|
4480
|
+
}
|
|
4481
|
+
return discriminatedUnionBranchOf(schema, source[schema.key]);
|
|
4482
|
+
}
|
|
4483
|
+
|
|
4484
|
+
/** The child of a source value at a segment, or `null` where there is none. */
|
|
4485
|
+
function childSource(source, segment) {
|
|
4486
|
+
var _source$segment;
|
|
4487
|
+
if (Array.isArray(source)) {
|
|
4488
|
+
var _source$index;
|
|
4489
|
+
var index = Number(segment);
|
|
4490
|
+
return Number.isInteger(index) ? (_source$index = source[index]) !== null && _source$index !== void 0 ? _source$index : null : null;
|
|
4491
|
+
}
|
|
4492
|
+
if (!isJsonObject(source)) {
|
|
4493
|
+
return null;
|
|
4494
|
+
}
|
|
4495
|
+
return (_source$segment = source[segment]) !== null && _source$segment !== void 0 ? _source$segment : null;
|
|
4496
|
+
}
|
|
4497
|
+
|
|
4498
|
+
/**
|
|
4499
|
+
* Whether `source` is a JSON object rather than an array or a primitive.
|
|
4500
|
+
*
|
|
4501
|
+
* A type predicate rather than the inline checks, because `Array.isArray` does
|
|
4502
|
+
* NOT narrow `JsonArray` out of `Json` — it is `readonly Json[]`, and the
|
|
4503
|
+
* built-in guard only narrows mutable arrays. Without this, every read of a
|
|
4504
|
+
* property would need an assertion.
|
|
4505
|
+
*/
|
|
4506
|
+
function isJsonObject(source) {
|
|
4507
|
+
return _typeof(source) === "object" && source !== null && !Array.isArray(source);
|
|
4508
|
+
}
|
|
4509
|
+
|
|
4061
4510
|
/**
|
|
4062
4511
|
* Local `yyyy-MM-dd`, which is the one thing this module used `date-fns` for.
|
|
4063
4512
|
*
|
|
@@ -4094,15 +4543,27 @@ function clampDateTimeString(value, options) {
|
|
|
4094
4543
|
}
|
|
4095
4544
|
return value;
|
|
4096
4545
|
}
|
|
4097
|
-
|
|
4546
|
+
|
|
4547
|
+
/**
|
|
4548
|
+
* What `emptyOf` cannot read off a serialized schema.
|
|
4549
|
+
*
|
|
4550
|
+
* The project's languages, and which one is being worked in. Neither is in the
|
|
4551
|
+
* schema: a locale-keyed record has one entry per language and the languages
|
|
4552
|
+
* are declared in the settings module, and "which language am I writing" is a
|
|
4553
|
+
* fact about the editor, not about the content. Optional throughout: a caller
|
|
4554
|
+
* that has no context gets an empty record and an unset locale, which
|
|
4555
|
+
* validation then reports, rather than wrong ones.
|
|
4556
|
+
*/
|
|
4557
|
+
|
|
4558
|
+
function emptyOf(schema, context) {
|
|
4098
4559
|
if (schema.type === "object") {
|
|
4099
4560
|
return Object.fromEntries(Object.keys(schema.items).map(function (key) {
|
|
4100
|
-
return [key, emptyOf(schema.items[key])];
|
|
4561
|
+
return [key, emptyOf(schema.items[key], context)];
|
|
4101
4562
|
}));
|
|
4102
4563
|
} else if (schema.type === "array") {
|
|
4103
4564
|
return [];
|
|
4104
4565
|
} else if (schema.type === "record") {
|
|
4105
|
-
return
|
|
4566
|
+
return emptyRecord(schema, context);
|
|
4106
4567
|
} else if (schema.type === "settings") {
|
|
4107
4568
|
// Not an object of empty sections: every settings key is optional, and
|
|
4108
4569
|
// absent IS the empty value. Filling the sections in would write a shape
|
|
@@ -4126,15 +4587,34 @@ function emptyOf(schema) {
|
|
|
4126
4587
|
}
|
|
4127
4588
|
} else if (schema.type === "route") {
|
|
4128
4589
|
return ""; // Empty string as default route value
|
|
4590
|
+
} else if (schema.type === "locale") {
|
|
4591
|
+
var _context$selectedLoca;
|
|
4592
|
+
// Which languages exist is in the settings module, which `emptyOf` has no
|
|
4593
|
+
// access to — it works from a serialized schema alone. So a caller that
|
|
4594
|
+
// has narrowed to one language says so and gets it; a caller that has not
|
|
4595
|
+
// gets the empty string, which is not a language and which validation
|
|
4596
|
+
// reports. Guessing `locales[0]` instead would file content under a
|
|
4597
|
+
// language nobody chose, which is the thing this whole feature exists to
|
|
4598
|
+
// make visible.
|
|
4599
|
+
return (_context$selectedLoca = context === null || context === void 0 ? void 0 : context.selectedLocale) !== null && _context$selectedLoca !== void 0 ? _context$selectedLoca : "";
|
|
4129
4600
|
} else if (schema.type === "file" || schema.type === "image") {
|
|
4130
4601
|
return null; // returning null is the only thing we can do, however, it means that the patches cannot be applied yet since that might fail
|
|
4131
4602
|
} else if (schema.type === "literal") {
|
|
4132
4603
|
return schema.value;
|
|
4133
|
-
} else if (schema.type === "union") {
|
|
4134
|
-
|
|
4135
|
-
|
|
4604
|
+
} else if (schema.type === "discriminated-union") {
|
|
4605
|
+
// The first variant is what a new value starts as. `s.discriminatedUnion`
|
|
4606
|
+
// requires one, so an empty `items` means a serialized schema that was not
|
|
4607
|
+
// built by it — say so rather than returning `undefined`, which is not
|
|
4608
|
+
// JSON and would be written into a patch as a missing key.
|
|
4609
|
+
if (schema.items.length === 0) {
|
|
4610
|
+
throw Error("Cannot create an empty value for a discriminated union with no variants");
|
|
4611
|
+
}
|
|
4612
|
+
return emptyOf(schema.items[0], context);
|
|
4613
|
+
} else if (schema.type === "enum") {
|
|
4614
|
+
if (schema.values.length === 0) {
|
|
4615
|
+
throw Error("Cannot create an empty value for an enum with no values");
|
|
4136
4616
|
}
|
|
4137
|
-
return schema.
|
|
4617
|
+
return schema.values[0];
|
|
4138
4618
|
} else if (schema.type === "date") {
|
|
4139
4619
|
return clampDateString(formatLocalDate(new Date()), schema.options);
|
|
4140
4620
|
} else if (schema.type === "dateTime") {
|
|
@@ -4155,6 +4635,32 @@ function emptyOf(schema) {
|
|
|
4155
4635
|
throw Error("Unexpected schema type: " + JSON.stringify(_exhaustiveCheck));
|
|
4156
4636
|
}
|
|
4157
4637
|
|
|
4638
|
+
/**
|
|
4639
|
+
* An empty record — with every key its schema declares already in it.
|
|
4640
|
+
*
|
|
4641
|
+
* An open record (`s.record(s.string(), item)`) starts empty, because there is
|
|
4642
|
+
* no key anyone could mean. A record whose key schema enumerates its keys is
|
|
4643
|
+
* the opposite: the keys are part of the schema, so an empty one is already
|
|
4644
|
+
* missing them, and handing back `{}` would create content that fails
|
|
4645
|
+
* validation the moment it is written.
|
|
4646
|
+
*
|
|
4647
|
+
* The entries are `null` rather than `emptyOf(item)`. A null entry reads as "not
|
|
4648
|
+
* filled in yet", which is what a language nobody has translated into IS —
|
|
4649
|
+
* whereas an entry of empty strings claims someone wrote it and left it blank,
|
|
4650
|
+
* and would count as translated in every list and filter downstream.
|
|
4651
|
+
*/
|
|
4652
|
+
function emptyRecord(schema, context) {
|
|
4653
|
+
var _context$locales;
|
|
4654
|
+
var declared = declaredKeySetOf(schema.key);
|
|
4655
|
+
if (declared === null) {
|
|
4656
|
+
return {};
|
|
4657
|
+
}
|
|
4658
|
+
var keys = declared.kind === "literals" ? declared.keys : (_context$locales = context === null || context === void 0 ? void 0 : context.locales) !== null && _context$locales !== void 0 ? _context$locales : [];
|
|
4659
|
+
return Object.fromEntries(keys.map(function (key) {
|
|
4660
|
+
return [key, null];
|
|
4661
|
+
}));
|
|
4662
|
+
}
|
|
4663
|
+
|
|
4158
4664
|
var toolNames = ["get_all_schema", "get_source", "search_content", "validate_content", "create_patch", "add_session_image_to_gallery", "remove_image_gallery_entry", "navigate_to", "get_current_context", "get_patches", "get_source_path_from_route", "set_session_name", "show_compare_view", "ask_user_question", "duplicate_source", "empty_at_path", "count_entries", "get_record_keys"];
|
|
4159
4665
|
|
|
4160
4666
|
function buildFileRefValue(filePath, metadata) {
|
|
@@ -4222,24 +4728,19 @@ function resolveSerializedSchemaAtPath(schema, path) {
|
|
|
4222
4728
|
schema: current,
|
|
4223
4729
|
remainingPath: path.slice(i)
|
|
4224
4730
|
};
|
|
4225
|
-
} else if (current.type === "union") {
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
if (resolved.kind !== "unresolved") return resolved;
|
|
4234
|
-
}
|
|
4235
|
-
} catch (err) {
|
|
4236
|
-
_iterator2.e(err);
|
|
4237
|
-
} finally {
|
|
4238
|
-
_iterator2.f();
|
|
4731
|
+
} else if (current.type === "discriminated-union") {
|
|
4732
|
+
var _iterator2 = _createForOfIteratorHelper(current.items),
|
|
4733
|
+
_step2;
|
|
4734
|
+
try {
|
|
4735
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
4736
|
+
var variant = _step2.value;
|
|
4737
|
+
var resolved = resolveSerializedSchemaAtPath(variant, path.slice(i));
|
|
4738
|
+
if (resolved.kind !== "unresolved") return resolved;
|
|
4239
4739
|
}
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4740
|
+
} catch (err) {
|
|
4741
|
+
_iterator2.e(err);
|
|
4742
|
+
} finally {
|
|
4743
|
+
_iterator2.f();
|
|
4243
4744
|
}
|
|
4244
4745
|
return {
|
|
4245
4746
|
kind: "unresolved"
|
|
@@ -4536,7 +5037,13 @@ function buildEmptyAtPathPatch(args, moduleSchema,
|
|
|
4536
5037
|
// Required, not optional: the occupied-key check below is the only thing
|
|
4537
5038
|
// standing between "scaffold an entry" and "delete the entry that was there",
|
|
4538
5039
|
// and an optional argument is one a caller forgets.
|
|
4539
|
-
moduleSource
|
|
5040
|
+
moduleSource,
|
|
5041
|
+
// The project's languages, for a locale-keyed record: its entries ARE the
|
|
5042
|
+
// languages, and they are declared in another module, so an empty one built
|
|
5043
|
+
// without them is `{}` — which the completeness rule then reports as every
|
|
5044
|
+
// language missing. Both callers can answer: the Studio from the context, the
|
|
5045
|
+
// MCP tools from the snapshot they already hold. See `EmptyOfContext`.
|
|
5046
|
+
context) {
|
|
4540
5047
|
var destinationSchema;
|
|
4541
5048
|
if (args.destinationPath.length === 0) {
|
|
4542
5049
|
destinationSchema = moduleSchema;
|
|
@@ -4582,7 +5089,7 @@ moduleSource) {
|
|
|
4582
5089
|
if (occupied) {
|
|
4583
5090
|
return occupied;
|
|
4584
5091
|
}
|
|
4585
|
-
var value = emptyOf(destinationSchema);
|
|
5092
|
+
var value = emptyOf(destinationSchema, context);
|
|
4586
5093
|
return safeParsePatch([{
|
|
4587
5094
|
op: decision.op,
|
|
4588
5095
|
path: args.destinationPath,
|
|
@@ -4773,6 +5280,8 @@ function isSkippableFixCode(fix) {
|
|
|
4773
5280
|
return true;
|
|
4774
5281
|
case "keyof:check-keys":
|
|
4775
5282
|
case "router:check-route":
|
|
5283
|
+
case "locale:check-locale":
|
|
5284
|
+
case "record:fill-keys":
|
|
4776
5285
|
case "jsonValues:extract-entry":
|
|
4777
5286
|
// `jsonValues:extract-entry` is an entry inlined in the `.val.ts`. The
|
|
4778
5287
|
// browser cannot fix it (that means writing a new `*.val.json` and
|
|
@@ -5168,8 +5677,20 @@ function traverseSchemaSource(source, schema, path, callback) {
|
|
|
5168
5677
|
return;
|
|
5169
5678
|
}
|
|
5170
5679
|
|
|
5171
|
-
// Handle
|
|
5172
|
-
if (schema.type === "
|
|
5680
|
+
// Handle enum: a leaf, like a literal with more than one allowed value
|
|
5681
|
+
if (schema.type === "enum") {
|
|
5682
|
+
if (typeof source === "string") {
|
|
5683
|
+
callback({
|
|
5684
|
+
source: source,
|
|
5685
|
+
schema: schema,
|
|
5686
|
+
path: path
|
|
5687
|
+
});
|
|
5688
|
+
}
|
|
5689
|
+
return;
|
|
5690
|
+
}
|
|
5691
|
+
|
|
5692
|
+
// Handle route and locale: both are plain strings at a leaf
|
|
5693
|
+
if (schema.type === "route" || schema.type === "locale") {
|
|
5173
5694
|
if (typeof source === "string") {
|
|
5174
5695
|
callback({
|
|
5175
5696
|
source: source,
|
|
@@ -5215,36 +5736,24 @@ function traverseSchemaSource(source, schema, path, callback) {
|
|
|
5215
5736
|
return;
|
|
5216
5737
|
}
|
|
5217
5738
|
|
|
5218
|
-
// Handle union
|
|
5219
|
-
if (schema.type === "union") {
|
|
5739
|
+
// Handle discriminated union: descend through the variant the value takes
|
|
5740
|
+
if (schema.type === "discriminated-union") {
|
|
5220
5741
|
var schemaKey = schema.key;
|
|
5221
|
-
if (
|
|
5222
|
-
|
|
5223
|
-
if (
|
|
5224
|
-
var
|
|
5225
|
-
|
|
5226
|
-
|
|
5227
|
-
|
|
5228
|
-
|
|
5229
|
-
|
|
5230
|
-
if ((itemKeySchema === null || itemKeySchema === void 0 ? void 0 : itemKeySchema.type) === "literal") {
|
|
5231
|
-
return itemKeySchema.value === itemKey;
|
|
5232
|
-
}
|
|
5233
|
-
return false;
|
|
5234
|
-
});
|
|
5235
|
-
if (schemaOfItem) {
|
|
5236
|
-
traverseSchemaSource(source, schemaOfItem, path, callback);
|
|
5742
|
+
if (source && _typeof(source) === "object" && !Array.isArray(source) && schemaKey in source) {
|
|
5743
|
+
var itemKey = source[schemaKey];
|
|
5744
|
+
if (typeof itemKey === "string") {
|
|
5745
|
+
var schemaOfItem = schema.items.filter(function (item) {
|
|
5746
|
+
return item.type === "object";
|
|
5747
|
+
}).find(function (item) {
|
|
5748
|
+
var itemKeySchema = item.items[schemaKey];
|
|
5749
|
+
if ((itemKeySchema === null || itemKeySchema === void 0 ? void 0 : itemKeySchema.type) === "literal") {
|
|
5750
|
+
return itemKeySchema.value === itemKey;
|
|
5237
5751
|
}
|
|
5238
|
-
|
|
5239
|
-
}
|
|
5240
|
-
} else {
|
|
5241
|
-
// Literal union - treat as primitive
|
|
5242
|
-
if (typeof source === "string") {
|
|
5243
|
-
callback({
|
|
5244
|
-
source: source,
|
|
5245
|
-
schema: schema,
|
|
5246
|
-
path: path
|
|
5752
|
+
return false;
|
|
5247
5753
|
});
|
|
5754
|
+
if (schemaOfItem) {
|
|
5755
|
+
traverseSchemaSource(source, schemaOfItem, path, callback);
|
|
5756
|
+
}
|
|
5248
5757
|
}
|
|
5249
5758
|
}
|
|
5250
5759
|
return;
|
|
@@ -5404,7 +5913,17 @@ function indexModule(searchIndex, moduleFilePath, source, schema) {
|
|
|
5404
5913
|
var label = "";
|
|
5405
5914
|
|
|
5406
5915
|
// Handle primitives
|
|
5407
|
-
if (schema.type === "string" || schema.type === "number" || schema.type === "boolean" || schema.type === "date" || schema.type === "dateTime" || schema.type === "color" || schema.type === "code" || schema.type === "keyOf" || schema.type === "route"
|
|
5916
|
+
if (schema.type === "string" || schema.type === "number" || schema.type === "boolean" || schema.type === "date" || schema.type === "dateTime" || schema.type === "color" || schema.type === "code" || schema.type === "keyOf" || schema.type === "route" ||
|
|
5917
|
+
// An enum's value is a string the editor chose; it is as searchable as
|
|
5918
|
+
// any other string leaf. The old string union was never indexed at all,
|
|
5919
|
+
// which is the gap this closes.
|
|
5920
|
+
schema.type === "enum" ||
|
|
5921
|
+
// A locale tag, for the same reason: it is what the editor picked and
|
|
5922
|
+
// what they see in the field, so searching "nb-NO" has to find the
|
|
5923
|
+
// Norwegian rows. `traverseSchemaSource` visits these, and visiting a
|
|
5924
|
+
// leaf only to index it as the empty string is worse than not visiting
|
|
5925
|
+
// it — it looks like content that does not exist.
|
|
5926
|
+
schema.type === "locale") {
|
|
5408
5927
|
var _source$toString, _source$toString2;
|
|
5409
5928
|
searchText = (_source$toString = source === null || source === void 0 ? void 0 : source.toString()) !== null && _source$toString !== void 0 ? _source$toString : "";
|
|
5410
5929
|
label = (_source$toString2 = source === null || source === void 0 ? void 0 : source.toString()) !== null && _source$toString2 !== void 0 ? _source$toString2 : "";
|
|
@@ -5545,4 +6064,4 @@ function performSearch(searchIndex, query) {
|
|
|
5545
6064
|
};
|
|
5546
6065
|
}
|
|
5547
6066
|
|
|
5548
|
-
export { Api, BinaryFileRef, CodeOptions, ColorOptions, DEFAULT_ERROR_MESSAGE, DateOptions, ENCODE_DEFAULTS, ENCODE_MIME_TYPE_OF, FileOptions, HistoricalCommit, HistoricalModule, HistoricalPatchSet, HistoryError, ImageEncodeOption, ImageOptions, JSONValue, JSON_ENTRIES_BATCH_MAX, ModuleComparison, NEVER_ENCODED, ParentRef$1 as ParentRef, Patch, PatchBlock, PatchGroup, PatchId, PatchJSON, RemirrorBr, RemirrorBulletList, RemirrorHeading, RemirrorImage, RemirrorJSON, RemirrorLinkMark, RemirrorListItem, RemirrorOrderedList, RemirrorParagraph, RemirrorText, RemirrorTextMark, RestoreVerdict, RichTextOptions, SerializedArraySchema, SerializedBooleanSchema, SerializedCodeSchema, SerializedColorSchema, SerializedDateSchema, SerializedDateTimeSchema, SerializedFileSchema, SerializedImageSchema, SerializedKeyOfSchema, SerializedLiteralSchema, SerializedNumberSchema, SerializedObjectSchema, SerializedRecordSchema, SerializedRichTextSchema, SerializedRouteSchema, SerializedSchema, SerializedSettingsSchema, SerializedStringSchema,
|
|
6067
|
+
export { Api, BinaryFileRef, CodeOptions, ColorOptions, DEFAULT_ERROR_MESSAGE, DateOptions, ENCODE_DEFAULTS, ENCODE_MIME_TYPE_OF, FileOptions, HistoricalCommit, HistoricalModule, HistoricalPatchSet, HistoryError, ImageEncodeOption, ImageOptions, JSONValue, JSON_ENTRIES_BATCH_MAX, ModuleComparison, NEVER_ENCODED, ParentRef$1 as ParentRef, Patch, PatchBlock, PatchGroup, PatchId, PatchJSON, RemirrorBr, RemirrorBulletList, RemirrorHeading, RemirrorImage, RemirrorJSON, RemirrorLinkMark, RemirrorListItem, RemirrorOrderedList, RemirrorParagraph, RemirrorText, RemirrorTextMark, RestoreVerdict, RichTextOptions, SCHEMA_SOURCE_FIXES, SerializedArraySchema, SerializedBooleanSchema, SerializedCodeSchema, SerializedColorSchema, SerializedDateSchema, SerializedDateTimeSchema, SerializedDiscriminatedUnionSchema, SerializedEnumSchema, SerializedFileSchema, SerializedImageSchema, SerializedKeyOfSchema, SerializedLiteralSchema, SerializedLocaleSchema, SerializedNumberSchema, SerializedObjectSchema, SerializedRecordSchema, SerializedRichTextSchema, SerializedRouteSchema, SerializedSchema, SerializedSettingsSchema, SerializedStringSchema, SharedValConfig, VAL_ENABLE_COOKIE_NAME, VAL_SESSION_COOKIE, VAL_STATE_COOKIE, ValCommit, ValDeployment, buildDuplicatePatch, buildEmptyAtPathPatch, buildFileRefValue, buildImageGalleryPatch, buildRemoveImageGalleryEntryPatch, buildSearchIndex, checkCompatibility, chooseEncoded, concatModulePath, createRegExpFromPattern, createSearchIndex, createValClient, declaredLocales, describeContainerAtPath, emptyOf, explainIncompatible, filterBlockingValidationErrors, filterRoutesByPatterns, findSimilar, fitWithin, flattenRichText, getErrorMessageFromUnknownJson, getFilenameFromRef, getInlineImgInfo, getKeyOfRecordAt, getRefParts, getRoutesOf, getRoutesWithModulePaths, getSourceAt, indexModule, isMimeTypeAccepted, isRemoteSchema, isSchemaSourceFixError, isSkippedSource, keyOfRecordPath, levenshtein, localeAt, newestCommitSha, partitionValidationErrors, performSearch, remirrorToRichTextSource, removeModule, resolveEncodeSettings, resolveSchemaSourceFixForError, resolveSchemaSourceFixes, resolveSerializedSchemaAtPath, richTextToRemirror, safeParsePatch, sourcePathOfChild, toolNames, traverseSchemaSource, urlOf, validateRoutePatterns, withExtension };
|