@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
|
@@ -989,19 +989,19 @@ var SerializedArraySchema = zod.z.lazy(function () {
|
|
|
989
989
|
opt: zod.z["boolean"]()
|
|
990
990
|
}));
|
|
991
991
|
});
|
|
992
|
-
var
|
|
993
|
-
return zod.z.
|
|
994
|
-
type: zod.z.literal("union"),
|
|
995
|
-
key: SerializedLiteralSchema,
|
|
996
|
-
items: zod.z.array(SerializedLiteralSchema),
|
|
997
|
-
opt: zod.z["boolean"]()
|
|
998
|
-
})), zod.z.object(getSitemapTree._objectSpread2(getSitemapTree._objectSpread2({}, commonSchemaFields), {}, {
|
|
999
|
-
type: zod.z.literal("union"),
|
|
992
|
+
var SerializedDiscriminatedUnionSchema = zod.z.lazy(function () {
|
|
993
|
+
return zod.z.object(getSitemapTree._objectSpread2(getSitemapTree._objectSpread2({}, commonSchemaFields), {}, {
|
|
994
|
+
type: zod.z.literal("discriminated-union"),
|
|
1000
995
|
key: zod.z.string(),
|
|
1001
996
|
items: zod.z.array(SerializedObjectSchema),
|
|
1002
997
|
opt: zod.z["boolean"]()
|
|
1003
|
-
}))
|
|
998
|
+
}));
|
|
1004
999
|
});
|
|
1000
|
+
var SerializedEnumSchema = zod.z.object(getSitemapTree._objectSpread2(getSitemapTree._objectSpread2({}, commonSchemaFields), {}, {
|
|
1001
|
+
type: zod.z.literal("enum"),
|
|
1002
|
+
values: zod.z.array(zod.z.string()),
|
|
1003
|
+
opt: zod.z["boolean"]()
|
|
1004
|
+
}));
|
|
1005
1005
|
var ImageEncodeOption = zod.z.union([zod.z.literal(false), zod.z.object({
|
|
1006
1006
|
type: zod.z.literal("webp"),
|
|
1007
1007
|
quality: zod.z.number().optional(),
|
|
@@ -1125,6 +1125,16 @@ var SerializedCodeSchema = zod.z.object(getSitemapTree._objectSpread2(getSitemap
|
|
|
1125
1125
|
options: CodeOptions.optional(),
|
|
1126
1126
|
opt: zod.z["boolean"]()
|
|
1127
1127
|
}));
|
|
1128
|
+
var SerializedLocaleSchema = zod.z.object({
|
|
1129
|
+
type: zod.z.literal("locale"),
|
|
1130
|
+
render: FieldRender,
|
|
1131
|
+
preview: zod.z.literal(true).optional(),
|
|
1132
|
+
opt: zod.z["boolean"](),
|
|
1133
|
+
customValidate: zod.z["boolean"]().optional(),
|
|
1134
|
+
readonly: zod.z["boolean"]().optional(),
|
|
1135
|
+
hidden: zod.z["boolean"]().optional(),
|
|
1136
|
+
description: zod.z.string().optional()
|
|
1137
|
+
});
|
|
1128
1138
|
var SerializedRouteSchema = zod.z.object(getSitemapTree._objectSpread2(getSitemapTree._objectSpread2({}, commonSchemaFields), {}, {
|
|
1129
1139
|
type: zod.z.literal("route"),
|
|
1130
1140
|
options: zod.z.object({
|
|
@@ -1150,10 +1160,15 @@ var SerializedSettingsSchema = zod.z.lazy(function () {
|
|
|
1150
1160
|
return zod.z.object(getSitemapTree._objectSpread2(getSitemapTree._objectSpread2({}, commonSchemaFields), {}, {
|
|
1151
1161
|
type: zod.z.literal("settings"),
|
|
1152
1162
|
items: zod.z.record(zod.z.string(), SerializedSchema),
|
|
1153
|
-
opt: zod.z["boolean"]()
|
|
1163
|
+
opt: zod.z["boolean"](),
|
|
1164
|
+
// Which section this is, where Val has rules about it beyond its keys.
|
|
1165
|
+
// Dropping it would leave the Studio's validation worker running every
|
|
1166
|
+
// field's own rules and none of the cross-field ones — see
|
|
1167
|
+
// `sectionValidators` in core/src/schema/settings.ts.
|
|
1168
|
+
section: zod.z.string().optional()
|
|
1154
1169
|
}));
|
|
1155
1170
|
});
|
|
1156
|
-
var SerializedSchema = zod.z.union([SerializedStringSchema, SerializedLiteralSchema, SerializedBooleanSchema, SerializedNumberSchema, SerializedObjectSchema, SerializedArraySchema,
|
|
1171
|
+
var SerializedSchema = zod.z.union([SerializedStringSchema, SerializedLiteralSchema, SerializedBooleanSchema, SerializedNumberSchema, SerializedObjectSchema, SerializedArraySchema, SerializedDiscriminatedUnionSchema, SerializedEnumSchema, SerializedRichTextSchema, SerializedRecordSchema, SerializedKeyOfSchema, SerializedRouteSchema, SerializedLocaleSchema, SerializedFileSchema, SerializedDateSchema, SerializedDateTimeSchema, SerializedColorSchema, SerializedCodeSchema, SerializedSettingsSchema, SerializedImageSchema]);
|
|
1157
1172
|
|
|
1158
1173
|
var ValCommit = zod.z.object({
|
|
1159
1174
|
commitSha: zod.z.string(),
|
|
@@ -1165,6 +1180,31 @@ var ValCommit = zod.z.object({
|
|
|
1165
1180
|
commitMessage: zod.z.string().nullable()
|
|
1166
1181
|
});
|
|
1167
1182
|
|
|
1183
|
+
var ValDeployment = zod.z.object({
|
|
1184
|
+
deploymentId: zod.z.string(),
|
|
1185
|
+
deploymentState: zod.z.string(),
|
|
1186
|
+
commitSha: zod.z.string(),
|
|
1187
|
+
updatedAt: zod.z.string(),
|
|
1188
|
+
createdAt: zod.z.string(),
|
|
1189
|
+
/**
|
|
1190
|
+
* The commit message, as the deployment's host reported it.
|
|
1191
|
+
*
|
|
1192
|
+
* Val's OWN publishes carry their message on the commit (`ValCommit`), and
|
|
1193
|
+
* that is the one the Studio prefers — it is the message Val wrote. This is
|
|
1194
|
+
* for every OTHER deployment: a developer's push, a merged pull request, a
|
|
1195
|
+
* revert. Those have no Val commit at all, so without this the deploy feed
|
|
1196
|
+
* could only name them by their short sha, and "what went out at 14:02?" had
|
|
1197
|
+
* no answer inside the Studio.
|
|
1198
|
+
*
|
|
1199
|
+
* Optional AND nullable, and the two mean different things: absent is a
|
|
1200
|
+
* content service that does not report messages (or an older one), null is
|
|
1201
|
+
* one that reports having none. Both render as the short sha, so nothing
|
|
1202
|
+
* depends on telling them apart — but a schema that demanded the field would
|
|
1203
|
+
* reject the whole deployment feed of a service that does not send it.
|
|
1204
|
+
*/
|
|
1205
|
+
commitMessage: zod.z.string().nullable().optional()
|
|
1206
|
+
});
|
|
1207
|
+
|
|
1168
1208
|
/**
|
|
1169
1209
|
* The wire shapes for reading history.
|
|
1170
1210
|
*
|
|
@@ -1304,7 +1344,7 @@ var ValConfig = zod.z.object({
|
|
|
1304
1344
|
gitCommit: zod.z.string().optional(),
|
|
1305
1345
|
gitBranch: zod.z.string().optional()
|
|
1306
1346
|
});
|
|
1307
|
-
var ValidationFixZ = zod.z.union([zod.z.literal("image:add-metadata"), zod.z.literal("image:check-metadata"), zod.z.literal("image:check-remote"), zod.z.literal("image:upload-remote"), zod.z.literal("image:download-remote"), zod.z.literal("images:check-remote"), zod.z.literal("images:upload-remote"), zod.z.literal("file:add-metadata"), zod.z.literal("file:check-metadata"), zod.z.literal("file:check-remote"), zod.z.literal("file:upload-remote"), zod.z.literal("file:download-remote"), zod.z.literal("files:check-remote"), zod.z.literal("files:upload-remote"), zod.z.literal("keyof:check-keys"), zod.z.literal("router:check-route"), zod.z.literal("images:check-unique-folder"), zod.z.literal("files:check-unique-folder"), zod.z.literal("images:check-all-files"), zod.z.literal("files:check-all-files"), zod.z.literal("jsonValues:extract-entry")]);
|
|
1347
|
+
var ValidationFixZ = zod.z.union([zod.z.literal("image:add-metadata"), zod.z.literal("image:check-metadata"), zod.z.literal("image:check-remote"), zod.z.literal("image:upload-remote"), zod.z.literal("image:download-remote"), zod.z.literal("images:check-remote"), zod.z.literal("images:upload-remote"), zod.z.literal("file:add-metadata"), zod.z.literal("file:check-metadata"), zod.z.literal("file:check-remote"), zod.z.literal("file:upload-remote"), zod.z.literal("file:download-remote"), zod.z.literal("files:check-remote"), zod.z.literal("files:upload-remote"), zod.z.literal("keyof:check-keys"), zod.z.literal("router:check-route"), zod.z.literal("locale:check-locale"), zod.z.literal("record:fill-keys"), zod.z.literal("images:check-unique-folder"), zod.z.literal("files:check-unique-folder"), zod.z.literal("images:check-all-files"), zod.z.literal("files:check-all-files"), zod.z.literal("jsonValues:extract-entry")]);
|
|
1308
1348
|
var ValidationError = zod.z.object({
|
|
1309
1349
|
message: zod.z.string(),
|
|
1310
1350
|
value: zod.z.unknown().optional(),
|
|
@@ -1757,6 +1797,21 @@ var Api = {
|
|
|
1757
1797
|
*/
|
|
1758
1798
|
headCommitSha: zod.z.string().optional(),
|
|
1759
1799
|
commits: zod.z.array(ValCommit),
|
|
1800
|
+
/**
|
|
1801
|
+
* The publishes the content service knows about.
|
|
1802
|
+
*
|
|
1803
|
+
* Declared, at last. `getStat` has always returned these in
|
|
1804
|
+
* `http` mode and the Studio has always read them - the response
|
|
1805
|
+
* validator strips unknown keys rather than rejecting them, and
|
|
1806
|
+
* the raw json is what the client hands back, so they arrived
|
|
1807
|
+
* while the contract said they could not. That was survivable
|
|
1808
|
+
* until a deployment started carrying a commit MESSAGE: a field
|
|
1809
|
+
* nobody has declared is a field the next person deletes.
|
|
1810
|
+
*
|
|
1811
|
+
* Optional, because a content service that reports no
|
|
1812
|
+
* deployments sends none.
|
|
1813
|
+
*/
|
|
1814
|
+
deployments: zod.z.array(ValDeployment).optional(),
|
|
1760
1815
|
config: ValConfig,
|
|
1761
1816
|
profileId: zod.z.string().nullable(),
|
|
1762
1817
|
mode: zod.z.union([zod.z.literal("http"), zod.z.literal("fs")])
|
|
@@ -3196,7 +3251,7 @@ var compatible = {
|
|
|
3196
3251
|
* `readonly Json[]` — so the check that reads naturally does not type. This
|
|
3197
3252
|
* predicate is that check, said once.
|
|
3198
3253
|
*/
|
|
3199
|
-
function isJsonObject(value) {
|
|
3254
|
+
function isJsonObject$1(value) {
|
|
3200
3255
|
return getSitemapTree._typeof(value) === "object" && value !== null && !Array.isArray(value);
|
|
3201
3256
|
}
|
|
3202
3257
|
function incompatible(reason) {
|
|
@@ -3249,21 +3304,11 @@ function explainIncompatible(reason) {
|
|
|
3249
3304
|
* not a failure: it is what makes the caller return `unknown` rather than guess.
|
|
3250
3305
|
*/
|
|
3251
3306
|
function variantOf(schema, value) {
|
|
3252
|
-
if (schema.type !== "union") {
|
|
3307
|
+
if (schema.type !== "discriminated-union") {
|
|
3253
3308
|
return undefined;
|
|
3254
3309
|
}
|
|
3255
|
-
// String union: the value IS the discriminator.
|
|
3256
|
-
if (typeof schema.key !== "string") {
|
|
3257
|
-
if (typeof value !== "string") {
|
|
3258
|
-
return undefined;
|
|
3259
|
-
}
|
|
3260
|
-
return schema.items.find(function (item) {
|
|
3261
|
-
return item.type === "literal" && item.value === value;
|
|
3262
|
-
});
|
|
3263
|
-
}
|
|
3264
|
-
// Object union: the discriminator is a literal at `key`.
|
|
3265
3310
|
var discriminator = schema.key;
|
|
3266
|
-
if (!isJsonObject(value)) {
|
|
3311
|
+
if (!isJsonObject$1(value)) {
|
|
3267
3312
|
return undefined;
|
|
3268
3313
|
}
|
|
3269
3314
|
var tag = value[discriminator];
|
|
@@ -3279,9 +3324,6 @@ function variantOf(schema, value) {
|
|
|
3279
3324
|
});
|
|
3280
3325
|
}
|
|
3281
3326
|
function describeVariant(schema, key) {
|
|
3282
|
-
if (schema.type === "literal") {
|
|
3283
|
-
return schema.value;
|
|
3284
|
-
}
|
|
3285
3327
|
if (schema.type === "object") {
|
|
3286
3328
|
var tag = schema.items[key];
|
|
3287
3329
|
if ((tag === null || tag === void 0 ? void 0 : tag.type) === "literal") {
|
|
@@ -3299,11 +3341,24 @@ function checkCompatibility(from, to) {
|
|
|
3299
3341
|
});
|
|
3300
3342
|
}
|
|
3301
3343
|
|
|
3344
|
+
// An enum's domain IS its schema, so the value decides: whatever the old
|
|
3345
|
+
// schema was — an enum, a literal, a plain string — the only question is
|
|
3346
|
+
// whether this string is still offered here.
|
|
3347
|
+
if (to.schema.type === "enum") {
|
|
3348
|
+
if (typeof from.value === "string" && to.schema.values.includes(from.value)) {
|
|
3349
|
+
return compatible;
|
|
3350
|
+
}
|
|
3351
|
+
return incompatible({
|
|
3352
|
+
kind: "no-matching-variant",
|
|
3353
|
+
variants: to.schema.values
|
|
3354
|
+
});
|
|
3355
|
+
}
|
|
3356
|
+
|
|
3302
3357
|
// A changed union is not itself disqualifying. What matters is whether the
|
|
3303
3358
|
// variant being restored still has somewhere to go — comparing the unions
|
|
3304
3359
|
// wholesale would refuse a restore that is perfectly safe.
|
|
3305
|
-
if (to.schema.type === "union") {
|
|
3306
|
-
var key =
|
|
3360
|
+
if (to.schema.type === "discriminated-union") {
|
|
3361
|
+
var key = to.schema.key;
|
|
3307
3362
|
var _iterator = getSitemapTree._createForOfIteratorHelper(to.schema.items),
|
|
3308
3363
|
_step;
|
|
3309
3364
|
try {
|
|
@@ -3328,9 +3383,9 @@ function checkCompatibility(from, to) {
|
|
|
3328
3383
|
});
|
|
3329
3384
|
}
|
|
3330
3385
|
|
|
3331
|
-
// Coming FROM a union into something that is not one: only the
|
|
3332
|
-
// value actually is matters, so narrow before comparing.
|
|
3333
|
-
if (from.schema.type === "union") {
|
|
3386
|
+
// Coming FROM a discriminated union into something that is not one: only the
|
|
3387
|
+
// variant this value actually is matters, so narrow before comparing.
|
|
3388
|
+
if (from.schema.type === "discriminated-union") {
|
|
3334
3389
|
var _variant = variantOf(from.schema, from.value);
|
|
3335
3390
|
if (_variant === undefined) {
|
|
3336
3391
|
return {
|
|
@@ -3343,6 +3398,25 @@ function checkCompatibility(from, to) {
|
|
|
3343
3398
|
value: from.value
|
|
3344
3399
|
}, to);
|
|
3345
3400
|
}
|
|
3401
|
+
|
|
3402
|
+
// Coming FROM an enum into something that is not one: the value it holds is
|
|
3403
|
+
// all the old schema contributes, so compare as that one value.
|
|
3404
|
+
if (from.schema.type === "enum") {
|
|
3405
|
+
if (typeof from.value !== "string") {
|
|
3406
|
+
return {
|
|
3407
|
+
status: "unknown",
|
|
3408
|
+
message: "The old value is not one of the options it was stored as, so we cannot tell whether it fits here."
|
|
3409
|
+
};
|
|
3410
|
+
}
|
|
3411
|
+
return checkCompatibility({
|
|
3412
|
+
schema: {
|
|
3413
|
+
type: "literal",
|
|
3414
|
+
value: from.value,
|
|
3415
|
+
opt: from.schema.opt
|
|
3416
|
+
},
|
|
3417
|
+
value: from.value
|
|
3418
|
+
}, to);
|
|
3419
|
+
}
|
|
3346
3420
|
if (from.schema.type !== to.schema.type) {
|
|
3347
3421
|
return incompatible({
|
|
3348
3422
|
kind: "type-changed",
|
|
@@ -3362,7 +3436,7 @@ function checkCompatibility(from, to) {
|
|
|
3362
3436
|
}
|
|
3363
3437
|
case "object":
|
|
3364
3438
|
{
|
|
3365
|
-
if (from.schema.type !== "object" || !isJsonObject(from.value)) {
|
|
3439
|
+
if (from.schema.type !== "object" || !isJsonObject$1(from.value)) {
|
|
3366
3440
|
return {
|
|
3367
3441
|
status: "unknown",
|
|
3368
3442
|
message: "The old value is not shaped like an object."
|
|
@@ -3465,7 +3539,7 @@ function checkCompatibility(from, to) {
|
|
|
3465
3539
|
}
|
|
3466
3540
|
case "record":
|
|
3467
3541
|
{
|
|
3468
|
-
if (from.schema.type !== "record" || !isJsonObject(from.value)) {
|
|
3542
|
+
if (from.schema.type !== "record" || !isJsonObject$1(from.value)) {
|
|
3469
3543
|
return {
|
|
3470
3544
|
status: "unknown",
|
|
3471
3545
|
message: "The old value is not a record."
|
|
@@ -3576,14 +3650,6 @@ var SharedValConfig = zod.z.object({
|
|
|
3576
3650
|
* Config that is shared between the client and server.
|
|
3577
3651
|
*/
|
|
3578
3652
|
|
|
3579
|
-
var ValDeployment = zod.z.object({
|
|
3580
|
-
deploymentId: zod.z.string(),
|
|
3581
|
-
deploymentState: zod.z.string(),
|
|
3582
|
-
commitSha: zod.z.string(),
|
|
3583
|
-
updatedAt: zod.z.string(),
|
|
3584
|
-
createdAt: zod.z.string()
|
|
3585
|
-
});
|
|
3586
|
-
|
|
3587
3653
|
/**
|
|
3588
3654
|
* Shared route validation utilities
|
|
3589
3655
|
*/
|
|
@@ -3756,6 +3822,16 @@ function findSimilar(key, targets) {
|
|
|
3756
3822
|
return a.distance - b.distance;
|
|
3757
3823
|
});
|
|
3758
3824
|
}
|
|
3825
|
+
/**
|
|
3826
|
+
* The record a `keyof:check-keys` error resolves against — the value and the
|
|
3827
|
+
* schema at the error's `sourcePath`.
|
|
3828
|
+
*
|
|
3829
|
+
* Exported for the one consumer that has to know what a resolution DEPENDED
|
|
3830
|
+
* on rather than what it concluded: `ValidationStore` re-reads the keys here
|
|
3831
|
+
* to decide whether a change to the referenced module can have moved the
|
|
3832
|
+
* answer. Keep this and {@link checkKeyIsValid} reading the same record, or the
|
|
3833
|
+
* store will invalidate on one record and the resolution answer from another.
|
|
3834
|
+
*/
|
|
3759
3835
|
function getKeyOfRecordAt(sourcePath, snapshot) {
|
|
3760
3836
|
var _Internal$splitModule = core.Internal.splitModuleFilePathAndModulePath(sourcePath),
|
|
3761
3837
|
_Internal$splitModule2 = _slicedToArray(_Internal$splitModule, 2),
|
|
@@ -3899,16 +3975,92 @@ function checkRouteIsValid(route, includePattern, excludePattern, snapshot) {
|
|
|
3899
3975
|
error: false
|
|
3900
3976
|
};
|
|
3901
3977
|
}
|
|
3978
|
+
|
|
3979
|
+
/**
|
|
3980
|
+
* The languages the project declares, from its settings module.
|
|
3981
|
+
*
|
|
3982
|
+
* Empty where there is no settings module, no `locales` section, or nothing in
|
|
3983
|
+
* it — all of which mean the same thing: this project has not said it is
|
|
3984
|
+
* translated.
|
|
3985
|
+
*/
|
|
3986
|
+
function declaredLocales(snapshot) {
|
|
3987
|
+
var _resolveSettingsModul = core.resolveSettingsModule(snapshot.schemas),
|
|
3988
|
+
moduleFilePath = _resolveSettingsModul.moduleFilePath;
|
|
3989
|
+
if (moduleFilePath === null) {
|
|
3990
|
+
return [];
|
|
3991
|
+
}
|
|
3992
|
+
var source = snapshot.sources[moduleFilePath];
|
|
3993
|
+
if (getSitemapTree._typeof(source) !== "object" || source === null || Array.isArray(source)) {
|
|
3994
|
+
return [];
|
|
3995
|
+
}
|
|
3996
|
+
var locales = source["locales"];
|
|
3997
|
+
if (getSitemapTree._typeof(locales) !== "object" || locales === null || Array.isArray(locales)) {
|
|
3998
|
+
return [];
|
|
3999
|
+
}
|
|
4000
|
+
var available = locales["available"];
|
|
4001
|
+
if (!Array.isArray(available)) {
|
|
4002
|
+
return [];
|
|
4003
|
+
}
|
|
4004
|
+
return available.filter(function (tag) {
|
|
4005
|
+
return typeof tag === "string";
|
|
4006
|
+
});
|
|
4007
|
+
}
|
|
4008
|
+
/**
|
|
4009
|
+
* The fixes {@link resolveSchemaSourceFixForError} answers for.
|
|
4010
|
+
*
|
|
4011
|
+
* A marker error carrying one of these is NOT a message: it says "ask the whole
|
|
4012
|
+
* project about this" and carries the value to ask with, because the schema
|
|
4013
|
+
* that raised it can only see its own module. Left unresolved, what a user sees
|
|
4014
|
+
* is the marker's own placeholder text — "should typically be processed by Val
|
|
4015
|
+
* internally … version mismatch" — which is alarming and says nothing.
|
|
4016
|
+
*
|
|
4017
|
+
* A list rather than a check per call site: every caller that resolves some of
|
|
4018
|
+
* these has to resolve all of them, and the two that leaked did so by adding a
|
|
4019
|
+
* fix here and not to a condition somewhere else.
|
|
4020
|
+
*/
|
|
4021
|
+
var SCHEMA_SOURCE_FIXES = ["keyof:check-keys", "router:check-route", "locale:check-locale", "record:fill-keys"];
|
|
4022
|
+
|
|
4023
|
+
/** Whether an error is a marker only the whole project can answer. */
|
|
4024
|
+
function isSchemaSourceFixError(error) {
|
|
4025
|
+
var _error$fixes;
|
|
4026
|
+
return ((_error$fixes = error.fixes) !== null && _error$fixes !== void 0 ? _error$fixes : []).some(function (fix) {
|
|
4027
|
+
return SCHEMA_SOURCE_FIXES.includes(fix);
|
|
4028
|
+
});
|
|
4029
|
+
}
|
|
4030
|
+
|
|
3902
4031
|
/**
|
|
3903
|
-
*
|
|
3904
|
-
*
|
|
4032
|
+
* The record a `keyof:check-keys` error resolves against, or null for any other
|
|
4033
|
+
* error — including a malformed marker, which
|
|
4034
|
+
* {@link resolveSchemaSourceFixForError} reports and this has nothing to say
|
|
4035
|
+
* about.
|
|
4036
|
+
*
|
|
4037
|
+
* For a consumer that needs to know what the resolution READS, not what it
|
|
4038
|
+
* concludes: `ValidationStore` keeps this per validated module, so that a change
|
|
4039
|
+
* to the referenced record can invalidate the module holding the reference.
|
|
4040
|
+
*/
|
|
4041
|
+
function keyOfRecordPath(error) {
|
|
4042
|
+
var _error$fixes2;
|
|
4043
|
+
if (!((_error$fixes2 = error.fixes) !== null && _error$fixes2 !== void 0 ? _error$fixes2 : []).includes("keyof:check-keys")) {
|
|
4044
|
+
return null;
|
|
4045
|
+
}
|
|
4046
|
+
var value = error.value;
|
|
4047
|
+
if (!value || getSitemapTree._typeof(value) !== "object") {
|
|
4048
|
+
return null;
|
|
4049
|
+
}
|
|
4050
|
+
var sourcePath = value.sourcePath;
|
|
4051
|
+
return typeof sourcePath === "string" ? sourcePath : null;
|
|
4052
|
+
}
|
|
4053
|
+
|
|
4054
|
+
/**
|
|
4055
|
+
* Resolves a single marker error (see {@link SCHEMA_SOURCE_FIXES}) against the
|
|
4056
|
+
* given schema/source snapshot. Returns:
|
|
3905
4057
|
* - null if the error is not one of these fixes (caller should pass through)
|
|
3906
|
-
* - { status: "resolved" } if the
|
|
4058
|
+
* - { status: "resolved" } if the reference is valid (drop error)
|
|
3907
4059
|
* - { status: "remaining"; error } if invalid (rewritten error to surface)
|
|
3908
4060
|
*/
|
|
3909
4061
|
function resolveSchemaSourceFixForError(error, snapshot) {
|
|
3910
|
-
var _error$
|
|
3911
|
-
var fixes = (_error$
|
|
4062
|
+
var _error$fixes3;
|
|
4063
|
+
var fixes = (_error$fixes3 = error.fixes) !== null && _error$fixes3 !== void 0 ? _error$fixes3 : [];
|
|
3912
4064
|
if (fixes.includes("keyof:check-keys")) {
|
|
3913
4065
|
if (!error.value) {
|
|
3914
4066
|
return {
|
|
@@ -3967,6 +4119,120 @@ function resolveSchemaSourceFixForError(error, snapshot) {
|
|
|
3967
4119
|
status: "resolved"
|
|
3968
4120
|
};
|
|
3969
4121
|
}
|
|
4122
|
+
if (fixes.includes("locale:check-locale")) {
|
|
4123
|
+
var value = error.value;
|
|
4124
|
+
if (getSitemapTree._typeof(value) !== "object" || value === null) {
|
|
4125
|
+
return {
|
|
4126
|
+
status: "remaining",
|
|
4127
|
+
error: getSitemapTree._objectSpread2(getSitemapTree._objectSpread2({}, error), {}, {
|
|
4128
|
+
message: "Expected locale validation error to have a 'value' object. Found: ".concat(getSitemapTree._typeof(value), ". ").concat(TYPE_ERROR_MESSAGE),
|
|
4129
|
+
typeError: true,
|
|
4130
|
+
fixes: undefined
|
|
4131
|
+
})
|
|
4132
|
+
};
|
|
4133
|
+
}
|
|
4134
|
+
var _ref6 = value,
|
|
4135
|
+
locale = _ref6.locale;
|
|
4136
|
+
if (typeof locale !== "string") {
|
|
4137
|
+
return {
|
|
4138
|
+
status: "remaining",
|
|
4139
|
+
error: getSitemapTree._objectSpread2(getSitemapTree._objectSpread2({}, error), {}, {
|
|
4140
|
+
message: "Expected locale validation error 'value' to have property 'locale' of type 'string'. Found: ".concat(getSitemapTree._typeof(locale), ". ").concat(TYPE_ERROR_MESSAGE),
|
|
4141
|
+
typeError: true,
|
|
4142
|
+
fixes: undefined
|
|
4143
|
+
})
|
|
4144
|
+
};
|
|
4145
|
+
}
|
|
4146
|
+
var available = declaredLocales(snapshot);
|
|
4147
|
+
if (available.length === 0) {
|
|
4148
|
+
return {
|
|
4149
|
+
status: "remaining",
|
|
4150
|
+
error: getSitemapTree._objectSpread2(getSitemapTree._objectSpread2({}, error), {}, {
|
|
4151
|
+
// The project has not said it is translated, so the value is not
|
|
4152
|
+
// wrong so much as premature — and the fix is in another file.
|
|
4153
|
+
message: "This project has no languages. Declare them under 'locales.available' in the settings module before using s.locale().",
|
|
4154
|
+
fixes: undefined
|
|
4155
|
+
})
|
|
4156
|
+
};
|
|
4157
|
+
}
|
|
4158
|
+
if (available.includes(locale)) {
|
|
4159
|
+
return {
|
|
4160
|
+
status: "resolved"
|
|
4161
|
+
};
|
|
4162
|
+
}
|
|
4163
|
+
return {
|
|
4164
|
+
status: "remaining",
|
|
4165
|
+
error: getSitemapTree._objectSpread2(getSitemapTree._objectSpread2({}, error), {}, {
|
|
4166
|
+
message: "'".concat(locale, "' is not one of this project's languages: ").concat(available.map(function (each) {
|
|
4167
|
+
return "'".concat(each, "'");
|
|
4168
|
+
}).join(", ")),
|
|
4169
|
+
fixes: undefined
|
|
4170
|
+
})
|
|
4171
|
+
};
|
|
4172
|
+
}
|
|
4173
|
+
if (fixes.includes("record:fill-keys")) {
|
|
4174
|
+
var _value = error.value;
|
|
4175
|
+
if (getSitemapTree._typeof(_value) !== "object" || _value === null) {
|
|
4176
|
+
return {
|
|
4177
|
+
status: "remaining",
|
|
4178
|
+
error: getSitemapTree._objectSpread2(getSitemapTree._objectSpread2({}, error), {}, {
|
|
4179
|
+
message: "Expected record key validation error to have a 'value' object. Found: ".concat(getSitemapTree._typeof(_value), ". ").concat(TYPE_ERROR_MESSAGE),
|
|
4180
|
+
typeError: true,
|
|
4181
|
+
fixes: undefined
|
|
4182
|
+
})
|
|
4183
|
+
};
|
|
4184
|
+
}
|
|
4185
|
+
var _ref7 = _value,
|
|
4186
|
+
present = _ref7.present,
|
|
4187
|
+
declared = _ref7.declared;
|
|
4188
|
+
if (!Array.isArray(present)) {
|
|
4189
|
+
return {
|
|
4190
|
+
status: "remaining",
|
|
4191
|
+
error: getSitemapTree._objectSpread2(getSitemapTree._objectSpread2({}, error), {}, {
|
|
4192
|
+
message: "Expected record key validation error 'value' to have property 'present' of type 'array'. Found: ".concat(getSitemapTree._typeof(present), ". ").concat(TYPE_ERROR_MESSAGE),
|
|
4193
|
+
typeError: true,
|
|
4194
|
+
fixes: undefined
|
|
4195
|
+
})
|
|
4196
|
+
};
|
|
4197
|
+
}
|
|
4198
|
+
var presentKeys = present.filter(function (key) {
|
|
4199
|
+
return typeof key === "string";
|
|
4200
|
+
});
|
|
4201
|
+
// A literal union brought its keys along; a locale record left them to be
|
|
4202
|
+
// read out of the settings module, which is the whole reason this check is
|
|
4203
|
+
// resolved here rather than in the schema.
|
|
4204
|
+
var declaredKeys = Array.isArray(declared) ? declared.filter(function (key) {
|
|
4205
|
+
return typeof key === "string";
|
|
4206
|
+
}) : declaredLocales(snapshot);
|
|
4207
|
+
if (declaredKeys.length === 0) {
|
|
4208
|
+
// A locale record on a project that has declared no languages. There is
|
|
4209
|
+
// nothing to require, and the locale field's own check already says the
|
|
4210
|
+
// project has not declared any — saying it twice on one record would not
|
|
4211
|
+
// add anything.
|
|
4212
|
+
return {
|
|
4213
|
+
status: "resolved"
|
|
4214
|
+
};
|
|
4215
|
+
}
|
|
4216
|
+
var missing = core.missingDeclaredKeys(declaredKeys, presentKeys);
|
|
4217
|
+
if (missing.length === 0) {
|
|
4218
|
+
return {
|
|
4219
|
+
status: "resolved"
|
|
4220
|
+
};
|
|
4221
|
+
}
|
|
4222
|
+
return {
|
|
4223
|
+
status: "remaining",
|
|
4224
|
+
error: getSitemapTree._objectSpread2(getSitemapTree._objectSpread2({}, error), {}, {
|
|
4225
|
+
message: "Missing ".concat(missing.length === 1 ? "key" : "keys", ": ").concat(missing.map(function (each) {
|
|
4226
|
+
return "'".concat(each, "'");
|
|
4227
|
+
}).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."),
|
|
4228
|
+
value: {
|
|
4229
|
+
missing: missing,
|
|
4230
|
+
declared: declaredKeys
|
|
4231
|
+
},
|
|
4232
|
+
fixes: undefined
|
|
4233
|
+
})
|
|
4234
|
+
};
|
|
4235
|
+
}
|
|
3970
4236
|
if (fixes.includes("router:check-route")) {
|
|
3971
4237
|
if (!error.value) {
|
|
3972
4238
|
return {
|
|
@@ -4028,10 +4294,10 @@ function asRegExpPattern(value) {
|
|
|
4028
4294
|
/**
|
|
4029
4295
|
* Apply schema/source fix resolution across a map of validation errors.
|
|
4030
4296
|
*
|
|
4031
|
-
* Errors
|
|
4032
|
-
*
|
|
4033
|
-
*
|
|
4034
|
-
*
|
|
4297
|
+
* Errors carrying one of {@link SCHEMA_SOURCE_FIXES} are resolved against the
|
|
4298
|
+
* in-memory schema/source snapshot — valid references drop the error, invalid
|
|
4299
|
+
* ones are rewritten with a "did you mean…" message and have their `fixes`
|
|
4300
|
+
* cleared (so downstream code reports them as plain validation errors).
|
|
4035
4301
|
* All other errors pass through untouched.
|
|
4036
4302
|
*
|
|
4037
4303
|
* Source paths with no remaining errors are removed from the result.
|
|
@@ -4065,6 +4331,189 @@ function resolveSchemaSourceFixes(validationErrors, snapshot) {
|
|
|
4065
4331
|
return result;
|
|
4066
4332
|
}
|
|
4067
4333
|
|
|
4334
|
+
/**
|
|
4335
|
+
* Which of the project's languages governs a path, or `null` for none.
|
|
4336
|
+
*
|
|
4337
|
+
* THE question the whole feature turns on. A locale scope is a subtree in one
|
|
4338
|
+
* language, and three things open one: a `locale` field on an object, a record
|
|
4339
|
+
* keyed by `s.locale()`, and a locale segment in a segmented key. Once this can
|
|
4340
|
+
* be answered from the schema and the source alone, everything downstream falls
|
|
4341
|
+
* out of it — the Studio's locale filter, deep links, `<html lang>`, and knowing
|
|
4342
|
+
* what to translate from and into.
|
|
4343
|
+
*
|
|
4344
|
+
* One implementation, so the Studio, the server and the validation worker cannot
|
|
4345
|
+
* disagree about what language a piece of content is in.
|
|
4346
|
+
*
|
|
4347
|
+
* `null` means no scope governs the path — which is the answer for most content
|
|
4348
|
+
* in most projects, and for every project that has not declared any languages.
|
|
4349
|
+
*/
|
|
4350
|
+
function localeAt(path, snapshot) {
|
|
4351
|
+
var available = declaredLocales(snapshot);
|
|
4352
|
+
if (available.length === 0) {
|
|
4353
|
+
// Nothing can be one of no languages. Answering `null` rather than reading
|
|
4354
|
+
// the content is also what makes this cheap for the projects that are not
|
|
4355
|
+
// translated at all.
|
|
4356
|
+
return null;
|
|
4357
|
+
}
|
|
4358
|
+
var _Internal$splitModule = core.Internal.splitModuleFilePathAndModulePath(path),
|
|
4359
|
+
_Internal$splitModule2 = _slicedToArray(_Internal$splitModule, 2),
|
|
4360
|
+
moduleFilePath = _Internal$splitModule2[0],
|
|
4361
|
+
modulePath = _Internal$splitModule2[1];
|
|
4362
|
+
var schema = snapshot.schemas[moduleFilePath];
|
|
4363
|
+
var source = snapshot.sources[moduleFilePath];
|
|
4364
|
+
if (schema === undefined || source === undefined) {
|
|
4365
|
+
return null;
|
|
4366
|
+
}
|
|
4367
|
+
var segments = modulePath ? core.Internal.splitModulePath(modulePath) : [];
|
|
4368
|
+
return walk(schema, source, segments, available);
|
|
4369
|
+
}
|
|
4370
|
+
|
|
4371
|
+
/**
|
|
4372
|
+
* Walk from a node towards `segments`, answering with the innermost scope.
|
|
4373
|
+
*
|
|
4374
|
+
* The scope is read on ARRIVAL at each node — the node the path names included,
|
|
4375
|
+
* not only the ones passed through on the way to it. So `localeAt` of a
|
|
4376
|
+
* scope-opening object is that object's own locale rather than its parent's,
|
|
4377
|
+
* and a path that stops AT a block still answers with the block's language.
|
|
4378
|
+
*
|
|
4379
|
+
* A scope may not contain another (see `localeScopeErrors`), so at most one of
|
|
4380
|
+
* these can fire on a well-formed path; taking the innermost is what makes the
|
|
4381
|
+
* answer well-defined while a project is mid-fix.
|
|
4382
|
+
*/
|
|
4383
|
+
function walk(schema, source, segments, available) {
|
|
4384
|
+
var entered = enter(schema, source, available);
|
|
4385
|
+
var locale = entered.locale;
|
|
4386
|
+
var currentSchema = entered.schema;
|
|
4387
|
+
var currentSource = source;
|
|
4388
|
+
var _iterator = getSitemapTree._createForOfIteratorHelper(segments),
|
|
4389
|
+
_step;
|
|
4390
|
+
try {
|
|
4391
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
4392
|
+
var segment = _step.value;
|
|
4393
|
+
if (currentSchema === undefined) {
|
|
4394
|
+
return locale;
|
|
4395
|
+
}
|
|
4396
|
+
if (currentSchema.type === "record") {
|
|
4397
|
+
var _currentSchema$key;
|
|
4398
|
+
if (((_currentSchema$key = currentSchema.key) === null || _currentSchema$key === void 0 ? void 0 : _currentSchema$key.type) === "locale") {
|
|
4399
|
+
// In a locale-keyed record the KEY is the language, so the segment we
|
|
4400
|
+
// are about to take is the answer.
|
|
4401
|
+
var resolved = core.localeOfValue(segment, available);
|
|
4402
|
+
if (resolved !== null) {
|
|
4403
|
+
locale = resolved;
|
|
4404
|
+
}
|
|
4405
|
+
}
|
|
4406
|
+
currentSchema = currentSchema.item;
|
|
4407
|
+
} else if (currentSchema.type === "array") {
|
|
4408
|
+
currentSchema = currentSchema.item;
|
|
4409
|
+
} else if (currentSchema.type === "object" || currentSchema.type === "settings") {
|
|
4410
|
+
currentSchema = currentSchema.items[segment];
|
|
4411
|
+
} else {
|
|
4412
|
+
// A leaf, or richtext's internal structure. Nothing below opens a scope.
|
|
4413
|
+
return locale;
|
|
4414
|
+
}
|
|
4415
|
+
currentSource = childSource(currentSource, segment);
|
|
4416
|
+
entered = enter(currentSchema, currentSource, available);
|
|
4417
|
+
currentSchema = entered.schema;
|
|
4418
|
+
if (entered.locale !== null) {
|
|
4419
|
+
locale = entered.locale;
|
|
4420
|
+
}
|
|
4421
|
+
}
|
|
4422
|
+
} catch (err) {
|
|
4423
|
+
_iterator.e(err);
|
|
4424
|
+
} finally {
|
|
4425
|
+
_iterator.f();
|
|
4426
|
+
}
|
|
4427
|
+
return locale;
|
|
4428
|
+
}
|
|
4429
|
+
|
|
4430
|
+
/**
|
|
4431
|
+
* Arrive at a node: resolve what it really is, and read the scope it opens.
|
|
4432
|
+
*
|
|
4433
|
+
* A discriminated union is a fork rather than a level — the variant the value
|
|
4434
|
+
* takes IS the node — so it is resolved here, before anything asks what the
|
|
4435
|
+
* node holds. Doing that on arrival rather than on the way down is the
|
|
4436
|
+
* difference between a block's own path answering with its language and
|
|
4437
|
+
* answering with nothing.
|
|
4438
|
+
*/
|
|
4439
|
+
function enter(schema, source, available) {
|
|
4440
|
+
var resolved = (schema === null || schema === void 0 ? void 0 : schema.type) === "discriminated-union" ? variantOfUnion(schema, source) : schema;
|
|
4441
|
+
return {
|
|
4442
|
+
schema: resolved,
|
|
4443
|
+
locale: resolved === undefined ? null : localeOfObjectField(resolved, source, available)
|
|
4444
|
+
};
|
|
4445
|
+
}
|
|
4446
|
+
|
|
4447
|
+
/**
|
|
4448
|
+
* The language an object's own `locale` field says it is in, if it has one.
|
|
4449
|
+
*
|
|
4450
|
+
* Reads the SOURCE, since unlike a record key the value is content rather than
|
|
4451
|
+
* part of the path. A field that has not been filled in, or holds something
|
|
4452
|
+
* that is not one of the project's languages, is not an answer — validation is
|
|
4453
|
+
* already reporting that, and guessing here would put a language in
|
|
4454
|
+
* `<html lang>` that nobody chose.
|
|
4455
|
+
*/
|
|
4456
|
+
function localeOfObjectField(schema, source, available) {
|
|
4457
|
+
if (schema.type !== "object" || !isJsonObject(source)) {
|
|
4458
|
+
return null;
|
|
4459
|
+
}
|
|
4460
|
+
for (var _i = 0, _Object$entries = Object.entries(schema.items); _i < _Object$entries.length; _i++) {
|
|
4461
|
+
var _Object$entries$_i = _slicedToArray(_Object$entries[_i], 2),
|
|
4462
|
+
key = _Object$entries$_i[0],
|
|
4463
|
+
item = _Object$entries$_i[1];
|
|
4464
|
+
if (item.type !== "locale") {
|
|
4465
|
+
continue;
|
|
4466
|
+
}
|
|
4467
|
+
var value = source[key];
|
|
4468
|
+
if (typeof value !== "string") {
|
|
4469
|
+
return null;
|
|
4470
|
+
}
|
|
4471
|
+
return core.localeOfValue(value, available);
|
|
4472
|
+
}
|
|
4473
|
+
return null;
|
|
4474
|
+
}
|
|
4475
|
+
|
|
4476
|
+
/**
|
|
4477
|
+
* The variant a value takes, or `undefined` if the tag matches none.
|
|
4478
|
+
*
|
|
4479
|
+
* The tag is read off the source here; picking the variant is
|
|
4480
|
+
* {@link discriminatedUnionBranchOf}, shared with the Studio's locale filter so
|
|
4481
|
+
* the two cannot disagree about which variant a row is. `s.enum()` never
|
|
4482
|
+
* reaches this — it is a leaf, with nothing under it to walk into.
|
|
4483
|
+
*/
|
|
4484
|
+
function variantOfUnion(schema, source) {
|
|
4485
|
+
if (!isJsonObject(source)) {
|
|
4486
|
+
return undefined;
|
|
4487
|
+
}
|
|
4488
|
+
return core.discriminatedUnionBranchOf(schema, source[schema.key]);
|
|
4489
|
+
}
|
|
4490
|
+
|
|
4491
|
+
/** The child of a source value at a segment, or `null` where there is none. */
|
|
4492
|
+
function childSource(source, segment) {
|
|
4493
|
+
var _source$segment;
|
|
4494
|
+
if (Array.isArray(source)) {
|
|
4495
|
+
var _source$index;
|
|
4496
|
+
var index = Number(segment);
|
|
4497
|
+
return Number.isInteger(index) ? (_source$index = source[index]) !== null && _source$index !== void 0 ? _source$index : null : null;
|
|
4498
|
+
}
|
|
4499
|
+
if (!isJsonObject(source)) {
|
|
4500
|
+
return null;
|
|
4501
|
+
}
|
|
4502
|
+
return (_source$segment = source[segment]) !== null && _source$segment !== void 0 ? _source$segment : null;
|
|
4503
|
+
}
|
|
4504
|
+
|
|
4505
|
+
/**
|
|
4506
|
+
* Whether `source` is a JSON object rather than an array or a primitive.
|
|
4507
|
+
*
|
|
4508
|
+
* A type predicate rather than the inline checks, because `Array.isArray` does
|
|
4509
|
+
* NOT narrow `JsonArray` out of `Json` — it is `readonly Json[]`, and the
|
|
4510
|
+
* built-in guard only narrows mutable arrays. Without this, every read of a
|
|
4511
|
+
* property would need an assertion.
|
|
4512
|
+
*/
|
|
4513
|
+
function isJsonObject(source) {
|
|
4514
|
+
return getSitemapTree._typeof(source) === "object" && source !== null && !Array.isArray(source);
|
|
4515
|
+
}
|
|
4516
|
+
|
|
4068
4517
|
/**
|
|
4069
4518
|
* Local `yyyy-MM-dd`, which is the one thing this module used `date-fns` for.
|
|
4070
4519
|
*
|
|
@@ -4101,15 +4550,27 @@ function clampDateTimeString(value, options) {
|
|
|
4101
4550
|
}
|
|
4102
4551
|
return value;
|
|
4103
4552
|
}
|
|
4104
|
-
|
|
4553
|
+
|
|
4554
|
+
/**
|
|
4555
|
+
* What `emptyOf` cannot read off a serialized schema.
|
|
4556
|
+
*
|
|
4557
|
+
* The project's languages, and which one is being worked in. Neither is in the
|
|
4558
|
+
* schema: a locale-keyed record has one entry per language and the languages
|
|
4559
|
+
* are declared in the settings module, and "which language am I writing" is a
|
|
4560
|
+
* fact about the editor, not about the content. Optional throughout: a caller
|
|
4561
|
+
* that has no context gets an empty record and an unset locale, which
|
|
4562
|
+
* validation then reports, rather than wrong ones.
|
|
4563
|
+
*/
|
|
4564
|
+
|
|
4565
|
+
function emptyOf(schema, context) {
|
|
4105
4566
|
if (schema.type === "object") {
|
|
4106
4567
|
return Object.fromEntries(Object.keys(schema.items).map(function (key) {
|
|
4107
|
-
return [key, emptyOf(schema.items[key])];
|
|
4568
|
+
return [key, emptyOf(schema.items[key], context)];
|
|
4108
4569
|
}));
|
|
4109
4570
|
} else if (schema.type === "array") {
|
|
4110
4571
|
return [];
|
|
4111
4572
|
} else if (schema.type === "record") {
|
|
4112
|
-
return
|
|
4573
|
+
return emptyRecord(schema, context);
|
|
4113
4574
|
} else if (schema.type === "settings") {
|
|
4114
4575
|
// Not an object of empty sections: every settings key is optional, and
|
|
4115
4576
|
// absent IS the empty value. Filling the sections in would write a shape
|
|
@@ -4133,15 +4594,34 @@ function emptyOf(schema) {
|
|
|
4133
4594
|
}
|
|
4134
4595
|
} else if (schema.type === "route") {
|
|
4135
4596
|
return ""; // Empty string as default route value
|
|
4597
|
+
} else if (schema.type === "locale") {
|
|
4598
|
+
var _context$selectedLoca;
|
|
4599
|
+
// Which languages exist is in the settings module, which `emptyOf` has no
|
|
4600
|
+
// access to — it works from a serialized schema alone. So a caller that
|
|
4601
|
+
// has narrowed to one language says so and gets it; a caller that has not
|
|
4602
|
+
// gets the empty string, which is not a language and which validation
|
|
4603
|
+
// reports. Guessing `locales[0]` instead would file content under a
|
|
4604
|
+
// language nobody chose, which is the thing this whole feature exists to
|
|
4605
|
+
// make visible.
|
|
4606
|
+
return (_context$selectedLoca = context === null || context === void 0 ? void 0 : context.selectedLocale) !== null && _context$selectedLoca !== void 0 ? _context$selectedLoca : "";
|
|
4136
4607
|
} else if (schema.type === "file" || schema.type === "image") {
|
|
4137
4608
|
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
|
|
4138
4609
|
} else if (schema.type === "literal") {
|
|
4139
4610
|
return schema.value;
|
|
4140
|
-
} else if (schema.type === "union") {
|
|
4141
|
-
|
|
4142
|
-
|
|
4611
|
+
} else if (schema.type === "discriminated-union") {
|
|
4612
|
+
// The first variant is what a new value starts as. `s.discriminatedUnion`
|
|
4613
|
+
// requires one, so an empty `items` means a serialized schema that was not
|
|
4614
|
+
// built by it — say so rather than returning `undefined`, which is not
|
|
4615
|
+
// JSON and would be written into a patch as a missing key.
|
|
4616
|
+
if (schema.items.length === 0) {
|
|
4617
|
+
throw Error("Cannot create an empty value for a discriminated union with no variants");
|
|
4618
|
+
}
|
|
4619
|
+
return emptyOf(schema.items[0], context);
|
|
4620
|
+
} else if (schema.type === "enum") {
|
|
4621
|
+
if (schema.values.length === 0) {
|
|
4622
|
+
throw Error("Cannot create an empty value for an enum with no values");
|
|
4143
4623
|
}
|
|
4144
|
-
return schema.
|
|
4624
|
+
return schema.values[0];
|
|
4145
4625
|
} else if (schema.type === "date") {
|
|
4146
4626
|
return clampDateString(formatLocalDate(new Date()), schema.options);
|
|
4147
4627
|
} else if (schema.type === "dateTime") {
|
|
@@ -4162,6 +4642,32 @@ function emptyOf(schema) {
|
|
|
4162
4642
|
throw Error("Unexpected schema type: " + JSON.stringify(_exhaustiveCheck));
|
|
4163
4643
|
}
|
|
4164
4644
|
|
|
4645
|
+
/**
|
|
4646
|
+
* An empty record — with every key its schema declares already in it.
|
|
4647
|
+
*
|
|
4648
|
+
* An open record (`s.record(s.string(), item)`) starts empty, because there is
|
|
4649
|
+
* no key anyone could mean. A record whose key schema enumerates its keys is
|
|
4650
|
+
* the opposite: the keys are part of the schema, so an empty one is already
|
|
4651
|
+
* missing them, and handing back `{}` would create content that fails
|
|
4652
|
+
* validation the moment it is written.
|
|
4653
|
+
*
|
|
4654
|
+
* The entries are `null` rather than `emptyOf(item)`. A null entry reads as "not
|
|
4655
|
+
* filled in yet", which is what a language nobody has translated into IS —
|
|
4656
|
+
* whereas an entry of empty strings claims someone wrote it and left it blank,
|
|
4657
|
+
* and would count as translated in every list and filter downstream.
|
|
4658
|
+
*/
|
|
4659
|
+
function emptyRecord(schema, context) {
|
|
4660
|
+
var _context$locales;
|
|
4661
|
+
var declared = core.declaredKeySetOf(schema.key);
|
|
4662
|
+
if (declared === null) {
|
|
4663
|
+
return {};
|
|
4664
|
+
}
|
|
4665
|
+
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 : [];
|
|
4666
|
+
return Object.fromEntries(keys.map(function (key) {
|
|
4667
|
+
return [key, null];
|
|
4668
|
+
}));
|
|
4669
|
+
}
|
|
4670
|
+
|
|
4165
4671
|
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"];
|
|
4166
4672
|
|
|
4167
4673
|
function buildFileRefValue(filePath, metadata) {
|
|
@@ -4229,24 +4735,19 @@ function resolveSerializedSchemaAtPath(schema, path) {
|
|
|
4229
4735
|
schema: current,
|
|
4230
4736
|
remainingPath: path.slice(i)
|
|
4231
4737
|
};
|
|
4232
|
-
} else if (current.type === "union") {
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
if (resolved.kind !== "unresolved") return resolved;
|
|
4241
|
-
}
|
|
4242
|
-
} catch (err) {
|
|
4243
|
-
_iterator2.e(err);
|
|
4244
|
-
} finally {
|
|
4245
|
-
_iterator2.f();
|
|
4738
|
+
} else if (current.type === "discriminated-union") {
|
|
4739
|
+
var _iterator2 = getSitemapTree._createForOfIteratorHelper(current.items),
|
|
4740
|
+
_step2;
|
|
4741
|
+
try {
|
|
4742
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
4743
|
+
var variant = _step2.value;
|
|
4744
|
+
var resolved = resolveSerializedSchemaAtPath(variant, path.slice(i));
|
|
4745
|
+
if (resolved.kind !== "unresolved") return resolved;
|
|
4246
4746
|
}
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4747
|
+
} catch (err) {
|
|
4748
|
+
_iterator2.e(err);
|
|
4749
|
+
} finally {
|
|
4750
|
+
_iterator2.f();
|
|
4250
4751
|
}
|
|
4251
4752
|
return {
|
|
4252
4753
|
kind: "unresolved"
|
|
@@ -4543,7 +5044,13 @@ function buildEmptyAtPathPatch(args, moduleSchema,
|
|
|
4543
5044
|
// Required, not optional: the occupied-key check below is the only thing
|
|
4544
5045
|
// standing between "scaffold an entry" and "delete the entry that was there",
|
|
4545
5046
|
// and an optional argument is one a caller forgets.
|
|
4546
|
-
moduleSource
|
|
5047
|
+
moduleSource,
|
|
5048
|
+
// The project's languages, for a locale-keyed record: its entries ARE the
|
|
5049
|
+
// languages, and they are declared in another module, so an empty one built
|
|
5050
|
+
// without them is `{}` — which the completeness rule then reports as every
|
|
5051
|
+
// language missing. Both callers can answer: the Studio from the context, the
|
|
5052
|
+
// MCP tools from the snapshot they already hold. See `EmptyOfContext`.
|
|
5053
|
+
context) {
|
|
4547
5054
|
var destinationSchema;
|
|
4548
5055
|
if (args.destinationPath.length === 0) {
|
|
4549
5056
|
destinationSchema = moduleSchema;
|
|
@@ -4589,7 +5096,7 @@ moduleSource) {
|
|
|
4589
5096
|
if (occupied) {
|
|
4590
5097
|
return occupied;
|
|
4591
5098
|
}
|
|
4592
|
-
var value = emptyOf(destinationSchema);
|
|
5099
|
+
var value = emptyOf(destinationSchema, context);
|
|
4593
5100
|
return safeParsePatch([{
|
|
4594
5101
|
op: decision.op,
|
|
4595
5102
|
path: args.destinationPath,
|
|
@@ -4780,6 +5287,8 @@ function isSkippableFixCode(fix) {
|
|
|
4780
5287
|
return true;
|
|
4781
5288
|
case "keyof:check-keys":
|
|
4782
5289
|
case "router:check-route":
|
|
5290
|
+
case "locale:check-locale":
|
|
5291
|
+
case "record:fill-keys":
|
|
4783
5292
|
case "jsonValues:extract-entry":
|
|
4784
5293
|
// `jsonValues:extract-entry` is an entry inlined in the `.val.ts`. The
|
|
4785
5294
|
// browser cannot fix it (that means writing a new `*.val.json` and
|
|
@@ -5175,8 +5684,20 @@ function traverseSchemaSource(source, schema, path, callback) {
|
|
|
5175
5684
|
return;
|
|
5176
5685
|
}
|
|
5177
5686
|
|
|
5178
|
-
// Handle
|
|
5179
|
-
if (schema.type === "
|
|
5687
|
+
// Handle enum: a leaf, like a literal with more than one allowed value
|
|
5688
|
+
if (schema.type === "enum") {
|
|
5689
|
+
if (typeof source === "string") {
|
|
5690
|
+
callback({
|
|
5691
|
+
source: source,
|
|
5692
|
+
schema: schema,
|
|
5693
|
+
path: path
|
|
5694
|
+
});
|
|
5695
|
+
}
|
|
5696
|
+
return;
|
|
5697
|
+
}
|
|
5698
|
+
|
|
5699
|
+
// Handle route and locale: both are plain strings at a leaf
|
|
5700
|
+
if (schema.type === "route" || schema.type === "locale") {
|
|
5180
5701
|
if (typeof source === "string") {
|
|
5181
5702
|
callback({
|
|
5182
5703
|
source: source,
|
|
@@ -5222,36 +5743,24 @@ function traverseSchemaSource(source, schema, path, callback) {
|
|
|
5222
5743
|
return;
|
|
5223
5744
|
}
|
|
5224
5745
|
|
|
5225
|
-
// Handle union
|
|
5226
|
-
if (schema.type === "union") {
|
|
5746
|
+
// Handle discriminated union: descend through the variant the value takes
|
|
5747
|
+
if (schema.type === "discriminated-union") {
|
|
5227
5748
|
var schemaKey = schema.key;
|
|
5228
|
-
if (
|
|
5229
|
-
|
|
5230
|
-
if (
|
|
5231
|
-
var
|
|
5232
|
-
|
|
5233
|
-
|
|
5234
|
-
|
|
5235
|
-
|
|
5236
|
-
|
|
5237
|
-
if ((itemKeySchema === null || itemKeySchema === void 0 ? void 0 : itemKeySchema.type) === "literal") {
|
|
5238
|
-
return itemKeySchema.value === itemKey;
|
|
5239
|
-
}
|
|
5240
|
-
return false;
|
|
5241
|
-
});
|
|
5242
|
-
if (schemaOfItem) {
|
|
5243
|
-
traverseSchemaSource(source, schemaOfItem, path, callback);
|
|
5749
|
+
if (source && getSitemapTree._typeof(source) === "object" && !Array.isArray(source) && schemaKey in source) {
|
|
5750
|
+
var itemKey = source[schemaKey];
|
|
5751
|
+
if (typeof itemKey === "string") {
|
|
5752
|
+
var schemaOfItem = schema.items.filter(function (item) {
|
|
5753
|
+
return item.type === "object";
|
|
5754
|
+
}).find(function (item) {
|
|
5755
|
+
var itemKeySchema = item.items[schemaKey];
|
|
5756
|
+
if ((itemKeySchema === null || itemKeySchema === void 0 ? void 0 : itemKeySchema.type) === "literal") {
|
|
5757
|
+
return itemKeySchema.value === itemKey;
|
|
5244
5758
|
}
|
|
5245
|
-
|
|
5246
|
-
}
|
|
5247
|
-
} else {
|
|
5248
|
-
// Literal union - treat as primitive
|
|
5249
|
-
if (typeof source === "string") {
|
|
5250
|
-
callback({
|
|
5251
|
-
source: source,
|
|
5252
|
-
schema: schema,
|
|
5253
|
-
path: path
|
|
5759
|
+
return false;
|
|
5254
5760
|
});
|
|
5761
|
+
if (schemaOfItem) {
|
|
5762
|
+
traverseSchemaSource(source, schemaOfItem, path, callback);
|
|
5763
|
+
}
|
|
5255
5764
|
}
|
|
5256
5765
|
}
|
|
5257
5766
|
return;
|
|
@@ -5411,7 +5920,17 @@ function indexModule(searchIndex, moduleFilePath, source, schema) {
|
|
|
5411
5920
|
var label = "";
|
|
5412
5921
|
|
|
5413
5922
|
// Handle primitives
|
|
5414
|
-
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"
|
|
5923
|
+
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" ||
|
|
5924
|
+
// An enum's value is a string the editor chose; it is as searchable as
|
|
5925
|
+
// any other string leaf. The old string union was never indexed at all,
|
|
5926
|
+
// which is the gap this closes.
|
|
5927
|
+
schema.type === "enum" ||
|
|
5928
|
+
// A locale tag, for the same reason: it is what the editor picked and
|
|
5929
|
+
// what they see in the field, so searching "nb-NO" has to find the
|
|
5930
|
+
// Norwegian rows. `traverseSchemaSource` visits these, and visiting a
|
|
5931
|
+
// leaf only to index it as the empty string is worse than not visiting
|
|
5932
|
+
// it — it looks like content that does not exist.
|
|
5933
|
+
schema.type === "locale") {
|
|
5415
5934
|
var _source$toString, _source$toString2;
|
|
5416
5935
|
searchText = (_source$toString = source === null || source === void 0 ? void 0 : source.toString()) !== null && _source$toString !== void 0 ? _source$toString : "";
|
|
5417
5936
|
label = (_source$toString2 = source === null || source === void 0 ? void 0 : source.toString()) !== null && _source$toString2 !== void 0 ? _source$toString2 : "";
|
|
@@ -5606,16 +6125,20 @@ exports.RemirrorText = RemirrorText;
|
|
|
5606
6125
|
exports.RemirrorTextMark = RemirrorTextMark;
|
|
5607
6126
|
exports.RestoreVerdict = RestoreVerdict;
|
|
5608
6127
|
exports.RichTextOptions = RichTextOptions;
|
|
6128
|
+
exports.SCHEMA_SOURCE_FIXES = SCHEMA_SOURCE_FIXES;
|
|
5609
6129
|
exports.SerializedArraySchema = SerializedArraySchema;
|
|
5610
6130
|
exports.SerializedBooleanSchema = SerializedBooleanSchema;
|
|
5611
6131
|
exports.SerializedCodeSchema = SerializedCodeSchema;
|
|
5612
6132
|
exports.SerializedColorSchema = SerializedColorSchema;
|
|
5613
6133
|
exports.SerializedDateSchema = SerializedDateSchema;
|
|
5614
6134
|
exports.SerializedDateTimeSchema = SerializedDateTimeSchema;
|
|
6135
|
+
exports.SerializedDiscriminatedUnionSchema = SerializedDiscriminatedUnionSchema;
|
|
6136
|
+
exports.SerializedEnumSchema = SerializedEnumSchema;
|
|
5615
6137
|
exports.SerializedFileSchema = SerializedFileSchema;
|
|
5616
6138
|
exports.SerializedImageSchema = SerializedImageSchema;
|
|
5617
6139
|
exports.SerializedKeyOfSchema = SerializedKeyOfSchema;
|
|
5618
6140
|
exports.SerializedLiteralSchema = SerializedLiteralSchema;
|
|
6141
|
+
exports.SerializedLocaleSchema = SerializedLocaleSchema;
|
|
5619
6142
|
exports.SerializedNumberSchema = SerializedNumberSchema;
|
|
5620
6143
|
exports.SerializedObjectSchema = SerializedObjectSchema;
|
|
5621
6144
|
exports.SerializedRecordSchema = SerializedRecordSchema;
|
|
@@ -5624,7 +6147,6 @@ exports.SerializedRouteSchema = SerializedRouteSchema;
|
|
|
5624
6147
|
exports.SerializedSchema = SerializedSchema;
|
|
5625
6148
|
exports.SerializedSettingsSchema = SerializedSettingsSchema;
|
|
5626
6149
|
exports.SerializedStringSchema = SerializedStringSchema;
|
|
5627
|
-
exports.SerializedUnionSchema = SerializedUnionSchema;
|
|
5628
6150
|
exports.SharedValConfig = SharedValConfig;
|
|
5629
6151
|
exports.VAL_ENABLE_COOKIE_NAME = VAL_ENABLE_COOKIE_NAME;
|
|
5630
6152
|
exports.VAL_SESSION_COOKIE = VAL_SESSION_COOKIE;
|
|
@@ -5643,6 +6165,7 @@ exports.concatModulePath = concatModulePath;
|
|
|
5643
6165
|
exports.createRegExpFromPattern = createRegExpFromPattern;
|
|
5644
6166
|
exports.createSearchIndex = createSearchIndex;
|
|
5645
6167
|
exports.createValClient = createValClient;
|
|
6168
|
+
exports.declaredLocales = declaredLocales;
|
|
5646
6169
|
exports.describeContainerAtPath = describeContainerAtPath;
|
|
5647
6170
|
exports.emptyOf = emptyOf;
|
|
5648
6171
|
exports.explainIncompatible = explainIncompatible;
|
|
@@ -5654,6 +6177,7 @@ exports.flattenRichText = flattenRichText;
|
|
|
5654
6177
|
exports.getErrorMessageFromUnknownJson = getErrorMessageFromUnknownJson;
|
|
5655
6178
|
exports.getFilenameFromRef = getFilenameFromRef;
|
|
5656
6179
|
exports.getInlineImgInfo = getInlineImgInfo;
|
|
6180
|
+
exports.getKeyOfRecordAt = getKeyOfRecordAt;
|
|
5657
6181
|
exports.getRefParts = getRefParts;
|
|
5658
6182
|
exports.getRoutesOf = getRoutesOf;
|
|
5659
6183
|
exports.getRoutesWithModulePaths = getRoutesWithModulePaths;
|
|
@@ -5661,8 +6185,11 @@ exports.getSourceAt = getSourceAt;
|
|
|
5661
6185
|
exports.indexModule = indexModule;
|
|
5662
6186
|
exports.isMimeTypeAccepted = isMimeTypeAccepted;
|
|
5663
6187
|
exports.isRemoteSchema = isRemoteSchema;
|
|
6188
|
+
exports.isSchemaSourceFixError = isSchemaSourceFixError;
|
|
5664
6189
|
exports.isSkippedSource = isSkippedSource;
|
|
6190
|
+
exports.keyOfRecordPath = keyOfRecordPath;
|
|
5665
6191
|
exports.levenshtein = levenshtein;
|
|
6192
|
+
exports.localeAt = localeAt;
|
|
5666
6193
|
exports.newestCommitSha = newestCommitSha;
|
|
5667
6194
|
exports.partitionValidationErrors = partitionValidationErrors;
|
|
5668
6195
|
exports.performSearch = performSearch;
|