@seamlet/astro 1.0.0 → 1.2.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 +14 -0
- package/README.md +113 -2
- package/dist/bridge.d.ts +2 -2
- package/dist/bridge.js +3 -2
- package/dist/chunk-HFPZVDST.js +78 -0
- package/dist/{chunk-QL4K4HR6.js → chunk-OCA2WYK3.js} +41 -0
- package/dist/{chunk-ZS32CW5F.js → chunk-UL2C2IB2.js} +392 -6
- package/dist/{chunk-SSECNMAD.js → chunk-Y4R4YV5O.js} +1 -1
- package/dist/cli.js +4 -4
- package/dist/index.js +8 -7
- package/dist/{messages-CvZhLRSE.d.ts → messages-C2OjqFmy.d.ts} +1 -1
- package/dist/{parse-content-Eg8yRq_t.d.ts → parse-content-Bnn6Wa-l.d.ts} +25 -4
- package/dist/preview-requests.d.ts +15 -1
- package/dist/preview-requests.js +7 -1
- package/dist/protocol.d.ts +3 -3
- package/dist/protocol.js +2 -2
- package/dist/routes/media.js +3 -1
- package/dist/schema.d.ts +53 -22
- package/dist/schema.js +35 -1
- package/dist/site-description-BnHrODQX.d.ts +258 -0
- package/dist/site.d.ts +54 -4
- package/dist/site.js +55 -9
- package/package.json +1 -1
- package/routes/preview.astro +23 -9
- package/dist/site-description-Cg5KNhhG.d.ts +0 -112
|
@@ -35,6 +35,9 @@ function url(options) {
|
|
|
35
35
|
function time(options) {
|
|
36
36
|
return { kind: "time", ...options };
|
|
37
37
|
}
|
|
38
|
+
function slug(options) {
|
|
39
|
+
return { kind: "slug", ...options };
|
|
40
|
+
}
|
|
38
41
|
function reference(options) {
|
|
39
42
|
return { kind: "reference", ...options };
|
|
40
43
|
}
|
|
@@ -52,6 +55,7 @@ function collection(options) {
|
|
|
52
55
|
function defaultValue(field) {
|
|
53
56
|
switch (field.kind) {
|
|
54
57
|
case "text":
|
|
58
|
+
case "slug":
|
|
55
59
|
return "";
|
|
56
60
|
case "toggle":
|
|
57
61
|
return false;
|
|
@@ -118,6 +122,7 @@ function resolveInsideField(field, segments, path) {
|
|
|
118
122
|
case "choices":
|
|
119
123
|
case "url":
|
|
120
124
|
case "time":
|
|
125
|
+
case "slug":
|
|
121
126
|
case "reference":
|
|
122
127
|
case "references":
|
|
123
128
|
return void 0;
|
|
@@ -353,6 +358,7 @@ function collectionIn(fields, content, names) {
|
|
|
353
358
|
case "choices":
|
|
354
359
|
case "url":
|
|
355
360
|
case "time":
|
|
361
|
+
case "slug":
|
|
356
362
|
case "reference":
|
|
357
363
|
case "references":
|
|
358
364
|
return void 0;
|
|
@@ -379,6 +385,7 @@ function collectionFieldAt(schema, path) {
|
|
|
379
385
|
case "choices":
|
|
380
386
|
case "url":
|
|
381
387
|
case "time":
|
|
388
|
+
case "slug":
|
|
382
389
|
case "reference":
|
|
383
390
|
case "references":
|
|
384
391
|
return void 0;
|
|
@@ -412,6 +419,7 @@ function withIdsIn(field, value, newId) {
|
|
|
412
419
|
case "choices":
|
|
413
420
|
case "url":
|
|
414
421
|
case "time":
|
|
422
|
+
case "slug":
|
|
415
423
|
case "reference":
|
|
416
424
|
case "references":
|
|
417
425
|
return value;
|
|
@@ -467,6 +475,7 @@ function issuesInField(field, value, path, idsOf) {
|
|
|
467
475
|
case "choices":
|
|
468
476
|
case "url":
|
|
469
477
|
case "time":
|
|
478
|
+
case "slug":
|
|
470
479
|
return [];
|
|
471
480
|
}
|
|
472
481
|
}
|
|
@@ -488,6 +497,146 @@ function stringsOf(value) {
|
|
|
488
497
|
return list.filter((id) => typeof id === "string");
|
|
489
498
|
}
|
|
490
499
|
|
|
500
|
+
// src/schema/slug-checks.ts
|
|
501
|
+
function slugFieldOf(item) {
|
|
502
|
+
const named = Object.entries(item).find(([, field]) => field.kind === "slug");
|
|
503
|
+
return named?.[0];
|
|
504
|
+
}
|
|
505
|
+
function takenSlugIssues(schema, content) {
|
|
506
|
+
return issuesInFields2(schema, content, []);
|
|
507
|
+
}
|
|
508
|
+
function issuesInFields2(fields, content, path) {
|
|
509
|
+
return Object.entries(fields).flatMap(
|
|
510
|
+
([name, field]) => issuesInField2(field, content[name], [...path, name])
|
|
511
|
+
);
|
|
512
|
+
}
|
|
513
|
+
function issuesInField2(field, value, path) {
|
|
514
|
+
switch (field.kind) {
|
|
515
|
+
case "group":
|
|
516
|
+
return isContentObject(value) ? issuesInFields2(field.fields, value, path) : [];
|
|
517
|
+
case "collection":
|
|
518
|
+
return issuesInCollection(field, recordsOf2(value), path);
|
|
519
|
+
case "text":
|
|
520
|
+
case "richText":
|
|
521
|
+
case "number":
|
|
522
|
+
case "date":
|
|
523
|
+
case "image":
|
|
524
|
+
case "link":
|
|
525
|
+
case "toggle":
|
|
526
|
+
case "choice":
|
|
527
|
+
case "choices":
|
|
528
|
+
case "url":
|
|
529
|
+
case "time":
|
|
530
|
+
case "slug":
|
|
531
|
+
case "reference":
|
|
532
|
+
case "references":
|
|
533
|
+
return [];
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
function issuesInCollection(collection2, records, path) {
|
|
537
|
+
const ownIssues = takenSlugsOf(collection2, records, path);
|
|
538
|
+
const innerIssues = records.flatMap(
|
|
539
|
+
(record, index) => issuesInFields2(collection2.item, record, [...path, index])
|
|
540
|
+
);
|
|
541
|
+
return [...ownIssues, ...innerIssues];
|
|
542
|
+
}
|
|
543
|
+
function takenSlugsOf(collection2, records, path) {
|
|
544
|
+
const slugName = slugFieldOf(collection2.item);
|
|
545
|
+
if (slugName === void 0) return [];
|
|
546
|
+
const ids = records.map((record) => record[RECORD_ID_KEY]);
|
|
547
|
+
const slugs = records.map((record) => record[slugName]);
|
|
548
|
+
return slugs.flatMap((slug2, index) => {
|
|
549
|
+
if (typeof slug2 !== "string" || slug2 === "") return [];
|
|
550
|
+
const isAnEarlierSlug = slugs.indexOf(slug2) < index;
|
|
551
|
+
const isAnotherId = ids.some(
|
|
552
|
+
(id, idIndex) => id === slug2 && idIndex !== index
|
|
553
|
+
);
|
|
554
|
+
const isTaken = isAnEarlierSlug || isAnotherId;
|
|
555
|
+
return isTaken ? [{ path: [...path, index, slugName], code: "taken-slug" }] : [];
|
|
556
|
+
});
|
|
557
|
+
}
|
|
558
|
+
function recordsOf2(value) {
|
|
559
|
+
return Array.isArray(value) ? value.filter(isContentObject) : [];
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// src/schema/slugs.ts
|
|
563
|
+
var PAGE_SEGMENT = "[a-z0-9][a-z0-9-]*";
|
|
564
|
+
var MAX_SLUG_LENGTH = 80;
|
|
565
|
+
var SLUG_PATTERN = new RegExp(`^${PAGE_SEGMENT}$`, "u");
|
|
566
|
+
var NOT_SLUG_CHARACTERS = /[^a-z0-9]+/gu;
|
|
567
|
+
var EDGE_HYPHENS = /^-+|-+$/gu;
|
|
568
|
+
var COMBINING_MARKS = new RegExp("\\p{M}", "gu");
|
|
569
|
+
var HYPHEN = "-";
|
|
570
|
+
var TRANSLITERATION = new Map(
|
|
571
|
+
Object.entries({
|
|
572
|
+
\u0430: "a",
|
|
573
|
+
\u0431: "b",
|
|
574
|
+
\u0432: "v",
|
|
575
|
+
\u0433: "g",
|
|
576
|
+
\u0434: "d",
|
|
577
|
+
\u0435: "e",
|
|
578
|
+
\u0451: "e",
|
|
579
|
+
\u0436: "zh",
|
|
580
|
+
\u0437: "z",
|
|
581
|
+
\u0438: "i",
|
|
582
|
+
\u0439: "y",
|
|
583
|
+
\u043A: "k",
|
|
584
|
+
\u043B: "l",
|
|
585
|
+
\u043C: "m",
|
|
586
|
+
\u043D: "n",
|
|
587
|
+
\u043E: "o",
|
|
588
|
+
\u043F: "p",
|
|
589
|
+
\u0440: "r",
|
|
590
|
+
\u0441: "s",
|
|
591
|
+
\u0442: "t",
|
|
592
|
+
\u0443: "u",
|
|
593
|
+
\u0444: "f",
|
|
594
|
+
\u0445: "h",
|
|
595
|
+
\u0446: "ts",
|
|
596
|
+
\u0447: "ch",
|
|
597
|
+
\u0448: "sh",
|
|
598
|
+
\u0449: "sch",
|
|
599
|
+
\u044A: "",
|
|
600
|
+
\u044B: "y",
|
|
601
|
+
\u044C: "",
|
|
602
|
+
\u044D: "e",
|
|
603
|
+
\u044E: "yu",
|
|
604
|
+
\u044F: "ya",
|
|
605
|
+
// Letters of Ukrainian and Belarusian words a Russian text may quote.
|
|
606
|
+
\u0456: "i",
|
|
607
|
+
\u0457: "yi",
|
|
608
|
+
\u0454: "ye",
|
|
609
|
+
\u0491: "g",
|
|
610
|
+
\u045E: "u",
|
|
611
|
+
// «Баня 6×4» is `banya-6x4`, the way its size is said.
|
|
612
|
+
"\xD7": "x"
|
|
613
|
+
})
|
|
614
|
+
);
|
|
615
|
+
var TRANSLITERATED = new RegExp(
|
|
616
|
+
`[${[...TRANSLITERATION.keys()].join("")}]`,
|
|
617
|
+
"gu"
|
|
618
|
+
);
|
|
619
|
+
function isSlug(value) {
|
|
620
|
+
return SLUG_PATTERN.test(value);
|
|
621
|
+
}
|
|
622
|
+
function slugOf(words) {
|
|
623
|
+
const latin = words.normalize("NFC").toLowerCase().replace(
|
|
624
|
+
TRANSLITERATED,
|
|
625
|
+
(character) => TRANSLITERATION.get(character) ?? character
|
|
626
|
+
).normalize("NFKD").replace(COMBINING_MARKS, "");
|
|
627
|
+
const hyphenated = latin.toLowerCase().replace(NOT_SLUG_CHARACTERS, HYPHEN).replace(EDGE_HYPHENS, "");
|
|
628
|
+
return shortened(hyphenated);
|
|
629
|
+
}
|
|
630
|
+
function shortened(slug2) {
|
|
631
|
+
if (slug2.length <= MAX_SLUG_LENGTH) return slug2;
|
|
632
|
+
const cut = slug2.slice(0, MAX_SLUG_LENGTH);
|
|
633
|
+
const isWordWhole = slug2[MAX_SLUG_LENGTH] === HYPHEN;
|
|
634
|
+
if (isWordWhole) return cut;
|
|
635
|
+
const lastHyphen = cut.lastIndexOf(HYPHEN);
|
|
636
|
+
const whole = lastHyphen > 0 ? cut.slice(0, lastHyphen) : cut;
|
|
637
|
+
return whole.replace(EDGE_HYPHENS, "");
|
|
638
|
+
}
|
|
639
|
+
|
|
491
640
|
// src/schema/parse-content.ts
|
|
492
641
|
var DATE_PATTERN = /^\d{4}-\d{2}-\d{2}$/u;
|
|
493
642
|
var TIME_PATTERN = /^(?:[01]\d|2[0-3]):[0-5]\d$/u;
|
|
@@ -501,9 +650,10 @@ function countCharacters(text2) {
|
|
|
501
650
|
function parseContent(schema, input) {
|
|
502
651
|
const parsed = parseFields(schema, input, []);
|
|
503
652
|
const missingRecords = missingRecordIssues(schema, parsed.value);
|
|
653
|
+
const takenSlugs = takenSlugIssues(schema, parsed.value);
|
|
504
654
|
return {
|
|
505
655
|
content: parsed.value,
|
|
506
|
-
issues: [...parsed.issues, ...missingRecords]
|
|
656
|
+
issues: [...parsed.issues, ...missingRecords, ...takenSlugs]
|
|
507
657
|
};
|
|
508
658
|
}
|
|
509
659
|
function parseFields(fields, input, path) {
|
|
@@ -547,6 +697,8 @@ function parseField(field, input, path) {
|
|
|
547
697
|
return parseUrl(field, input, path);
|
|
548
698
|
case "time":
|
|
549
699
|
return parseTime(field, input, path);
|
|
700
|
+
case "slug":
|
|
701
|
+
return parseSlug(field, input, path);
|
|
550
702
|
case "reference":
|
|
551
703
|
return parseReference(field, input, path);
|
|
552
704
|
case "references":
|
|
@@ -724,6 +876,17 @@ function parseTime(field, input, path) {
|
|
|
724
876
|
}
|
|
725
877
|
return valid(input);
|
|
726
878
|
}
|
|
879
|
+
function parseSlug(field, input, path) {
|
|
880
|
+
if (typeof input !== "string") {
|
|
881
|
+
return invalidType(defaultValue(field), path);
|
|
882
|
+
}
|
|
883
|
+
if (input === "") {
|
|
884
|
+
return valid(input);
|
|
885
|
+
}
|
|
886
|
+
const formatIssues = isSlug(input) ? [] : [{ path, code: "invalid-slug" }];
|
|
887
|
+
const lengthIssues = tooLongIssues(MAX_SLUG_LENGTH, input, path);
|
|
888
|
+
return { value: input, issues: [...formatIssues, ...lengthIssues] };
|
|
889
|
+
}
|
|
727
890
|
function parseCollection(field, input, path) {
|
|
728
891
|
if (!Array.isArray(input)) {
|
|
729
892
|
return invalidType(defaultValue(field), path);
|
|
@@ -863,6 +1026,30 @@ function openingHoursField(options = {}) {
|
|
|
863
1026
|
}
|
|
864
1027
|
});
|
|
865
1028
|
}
|
|
1029
|
+
function productFields() {
|
|
1030
|
+
return {
|
|
1031
|
+
name: text({ label: "\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435", maxLength: 120 }),
|
|
1032
|
+
slug: slug({ label: "\u0410\u0434\u0440\u0435\u0441 \u0441\u0442\u0440\u0430\u043D\u0438\u0446\u044B" }),
|
|
1033
|
+
photos: collection({
|
|
1034
|
+
label: "\u0424\u043E\u0442\u043E",
|
|
1035
|
+
item: { photo: image({ label: "\u0424\u043E\u0442\u043E" }) }
|
|
1036
|
+
}),
|
|
1037
|
+
summary: richText({ label: "\u041A\u0440\u0430\u0442\u043A\u043E", inline: true, maxLength: 200 }),
|
|
1038
|
+
description: richText({ label: "\u041E\u043F\u0438\u0441\u0430\u043D\u0438\u0435" }),
|
|
1039
|
+
price: number({ label: "\u0426\u0435\u043D\u0430, \u20BD", min: 0 }),
|
|
1040
|
+
priceNote: text({ label: "\u0423\u0442\u043E\u0447\u043D\u0435\u043D\u0438\u0435 \u0446\u0435\u043D\u044B", maxLength: 40 }),
|
|
1041
|
+
characteristics: collection({
|
|
1042
|
+
label: "\u0425\u0430\u0440\u0430\u043A\u0442\u0435\u0440\u0438\u0441\u0442\u0438\u043A\u0438",
|
|
1043
|
+
itemTitle: "name",
|
|
1044
|
+
item: {
|
|
1045
|
+
name: text({ label: "\u041D\u0430\u0437\u0432\u0430\u043D\u0438\u0435", maxLength: 60 }),
|
|
1046
|
+
value: text({ label: "\u0417\u043D\u0430\u0447\u0435\u043D\u0438\u0435", maxLength: 120 })
|
|
1047
|
+
}
|
|
1048
|
+
}),
|
|
1049
|
+
isHidden: toggle({ label: "\u0421\u043A\u0440\u044B\u0442\u044C \u0441 \u0441\u0430\u0439\u0442\u0430" }),
|
|
1050
|
+
seo: seoFields()
|
|
1051
|
+
};
|
|
1052
|
+
}
|
|
866
1053
|
|
|
867
1054
|
// src/schema/read-fields.ts
|
|
868
1055
|
var TITLE_KINDS = /* @__PURE__ */ new Set([
|
|
@@ -876,7 +1063,7 @@ function readFields(input) {
|
|
|
876
1063
|
function checkFields(input) {
|
|
877
1064
|
const reading = readFieldsAt(input, []);
|
|
878
1065
|
if (!reading.isRead) return { status: "invalid", problem: reading.problem };
|
|
879
|
-
const problem = firstUnknownCollection(reading.value, reading.value, []);
|
|
1066
|
+
const problem = firstUnknownCollection(reading.value, reading.value, []) ?? firstMisplacedSlug(reading.value, []);
|
|
880
1067
|
return problem === void 0 ? { status: "read", fields: reading.value } : { status: "invalid", problem };
|
|
881
1068
|
}
|
|
882
1069
|
function readFieldsAt(input, path) {
|
|
@@ -922,6 +1109,7 @@ function readFieldOfKind(field) {
|
|
|
922
1109
|
case "toggle":
|
|
923
1110
|
case "url":
|
|
924
1111
|
case "time":
|
|
1112
|
+
case "slug":
|
|
925
1113
|
return read({ kind, label });
|
|
926
1114
|
case "choice":
|
|
927
1115
|
case "choices":
|
|
@@ -1002,9 +1190,51 @@ function unknownCollectionIn(schema, field, path) {
|
|
|
1002
1190
|
case "choices":
|
|
1003
1191
|
case "url":
|
|
1004
1192
|
case "time":
|
|
1193
|
+
case "slug":
|
|
1194
|
+
return void 0;
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
function firstMisplacedSlug(fields, path) {
|
|
1198
|
+
for (const [name, field] of Object.entries(fields)) {
|
|
1199
|
+
const problem = misplacedSlugIn(field, [...path, name]);
|
|
1200
|
+
if (problem !== void 0) return problem;
|
|
1201
|
+
}
|
|
1202
|
+
return void 0;
|
|
1203
|
+
}
|
|
1204
|
+
function misplacedSlugIn(field, path) {
|
|
1205
|
+
switch (field.kind) {
|
|
1206
|
+
case "slug":
|
|
1207
|
+
return { path, reason: "misplaced-slug" };
|
|
1208
|
+
case "group":
|
|
1209
|
+
return firstMisplacedSlug(field.fields, path);
|
|
1210
|
+
case "collection":
|
|
1211
|
+
return misplacedSlugInRecord(field.item, path);
|
|
1212
|
+
case "text":
|
|
1213
|
+
case "richText":
|
|
1214
|
+
case "number":
|
|
1215
|
+
case "date":
|
|
1216
|
+
case "image":
|
|
1217
|
+
case "link":
|
|
1218
|
+
case "toggle":
|
|
1219
|
+
case "choice":
|
|
1220
|
+
case "choices":
|
|
1221
|
+
case "url":
|
|
1222
|
+
case "time":
|
|
1223
|
+
case "reference":
|
|
1224
|
+
case "references":
|
|
1005
1225
|
return void 0;
|
|
1006
1226
|
}
|
|
1007
1227
|
}
|
|
1228
|
+
function misplacedSlugInRecord(item, path) {
|
|
1229
|
+
const fields = Object.entries(item);
|
|
1230
|
+
const slugNames = fields.filter(([, field]) => field.kind === "slug").map(([name]) => name);
|
|
1231
|
+
const [, secondSlug] = slugNames;
|
|
1232
|
+
if (secondSlug !== void 0) {
|
|
1233
|
+
return { path: [...path, secondSlug], reason: "misplaced-slug" };
|
|
1234
|
+
}
|
|
1235
|
+
const otherFields = fields.filter(([, field]) => field.kind !== "slug");
|
|
1236
|
+
return firstMisplacedSlug(Object.fromEntries(otherFields), path);
|
|
1237
|
+
}
|
|
1008
1238
|
function referencesCollection(schema, field) {
|
|
1009
1239
|
return collectionFieldAt(schema, field.collection) !== void 0;
|
|
1010
1240
|
}
|
|
@@ -1031,6 +1261,7 @@ var FIELD_KINDS = {
|
|
|
1031
1261
|
choices: true,
|
|
1032
1262
|
url: true,
|
|
1033
1263
|
time: true,
|
|
1264
|
+
slug: true,
|
|
1034
1265
|
reference: true,
|
|
1035
1266
|
references: true,
|
|
1036
1267
|
group: true,
|
|
@@ -1094,9 +1325,71 @@ function originOf(value) {
|
|
|
1094
1325
|
return WEB_PROTOCOLS.has(url2.protocol) ? url2.origin : void 0;
|
|
1095
1326
|
}
|
|
1096
1327
|
|
|
1328
|
+
// src/schema/record-pages.ts
|
|
1329
|
+
var RECORD_PLACEHOLDER = "[record]";
|
|
1330
|
+
var RECORD_PAGE_PATH = new RegExp(
|
|
1331
|
+
`^(/${PAGE_SEGMENT})+/${escaped(RECORD_PLACEHOLDER)}$`,
|
|
1332
|
+
"u"
|
|
1333
|
+
);
|
|
1334
|
+
var PAGE_PATH_SEPARATOR = "/";
|
|
1335
|
+
var NOT_FOUND = -1;
|
|
1336
|
+
function recordPages(schema, options) {
|
|
1337
|
+
const { shows, ...described } = options;
|
|
1338
|
+
const collection2 = collectionFieldAt(schema, described.collection);
|
|
1339
|
+
if (collection2 === void 0) {
|
|
1340
|
+
throw new Error(
|
|
1341
|
+
`@seamlet/astro: the schema has no collection "${described.collection}" for the pages at "${described.path}"`
|
|
1342
|
+
);
|
|
1343
|
+
}
|
|
1344
|
+
const isShown = (record) => shows === void 0 || shows(record);
|
|
1345
|
+
const pathOf = (record) => {
|
|
1346
|
+
const address = isShown(record) ? recordAddressOf(collection2, record) : void 0;
|
|
1347
|
+
return address === void 0 ? void 0 : recordPagePath(described.path, address);
|
|
1348
|
+
};
|
|
1349
|
+
return { ...described, isShown, pathOf };
|
|
1350
|
+
}
|
|
1351
|
+
function isRecordPagePath(path) {
|
|
1352
|
+
return typeof path === "string" && RECORD_PAGE_PATH.test(path);
|
|
1353
|
+
}
|
|
1354
|
+
function recordAddressOf(collection2, record) {
|
|
1355
|
+
const slugName = slugFieldOf(collection2.item);
|
|
1356
|
+
const slug2 = slugName === void 0 ? void 0 : record[slugName];
|
|
1357
|
+
if (typeof slug2 === "string" && isSlug(slug2)) return slug2;
|
|
1358
|
+
const id = record[RECORD_ID_KEY];
|
|
1359
|
+
return isRecordId(id) ? id : void 0;
|
|
1360
|
+
}
|
|
1361
|
+
function recordPagePath(pagePath, address) {
|
|
1362
|
+
return pagePath.replace(RECORD_PLACEHOLDER, address);
|
|
1363
|
+
}
|
|
1364
|
+
function recordPageAt(pages, path) {
|
|
1365
|
+
for (const page of pages) {
|
|
1366
|
+
const address = addressUnder(page.path, path);
|
|
1367
|
+
if (address !== void 0) return { page, address };
|
|
1368
|
+
}
|
|
1369
|
+
return void 0;
|
|
1370
|
+
}
|
|
1371
|
+
function recordAt(collection2, records, address) {
|
|
1372
|
+
const pageIndex = records.findIndex(
|
|
1373
|
+
(record2) => recordAddressOf(collection2, record2) === address
|
|
1374
|
+
);
|
|
1375
|
+
const index = pageIndex === NOT_FOUND ? records.findIndex((record2) => record2[RECORD_ID_KEY] === address) : pageIndex;
|
|
1376
|
+
const record = records[index];
|
|
1377
|
+
return record === void 0 ? void 0 : { record, index };
|
|
1378
|
+
}
|
|
1379
|
+
function addressUnder(recordPagePath2, path) {
|
|
1380
|
+
const prefix = recordPagePath2.slice(0, -RECORD_PLACEHOLDER.length);
|
|
1381
|
+
if (!path.startsWith(prefix)) return void 0;
|
|
1382
|
+
const address = path.slice(prefix.length);
|
|
1383
|
+
const isOneSegment = address !== "" && !address.includes(PAGE_PATH_SEPARATOR);
|
|
1384
|
+
return isOneSegment ? address : void 0;
|
|
1385
|
+
}
|
|
1386
|
+
function escaped(text2) {
|
|
1387
|
+
return text2.replace(/[[\]]/gu, "\\$&");
|
|
1388
|
+
}
|
|
1389
|
+
|
|
1097
1390
|
// src/schema/site-description.ts
|
|
1098
1391
|
var SITE_DESCRIPTION_PATH = "/seamlet/site.json";
|
|
1099
|
-
var PAGE_PATH =
|
|
1392
|
+
var PAGE_PATH = new RegExp(`^(/${PAGE_SEGMENT})+$`, "u");
|
|
1100
1393
|
var HOME_PAGE_PATH = "/";
|
|
1101
1394
|
function readSiteDescription(input) {
|
|
1102
1395
|
const reading = checkSiteDescription(input);
|
|
@@ -1113,13 +1406,18 @@ function checkSiteDescription(input) {
|
|
|
1113
1406
|
}
|
|
1114
1407
|
const initial = parseContent(schema.fields, input["initialContent"]);
|
|
1115
1408
|
const pages = checkPages(schema.fields, input["pages"]);
|
|
1409
|
+
const recordPages2 = checkRecordPages(schema.fields, input["recordPages"]);
|
|
1116
1410
|
const problems = [
|
|
1117
1411
|
...nameProblems,
|
|
1118
1412
|
...initialContentProblems(initial.issues),
|
|
1119
|
-
...pages.problems
|
|
1413
|
+
...pages.problems,
|
|
1414
|
+
...recordPages2.problems,
|
|
1415
|
+
...placementProblems(pages.pages ?? [], recordPages2.pages ?? []),
|
|
1416
|
+
...addressProblems(schema.fields, initial.content, recordPages2.pages ?? [])
|
|
1120
1417
|
];
|
|
1121
1418
|
const isNamed = isSiteId(id) && isText(title);
|
|
1122
|
-
|
|
1419
|
+
const isWhole = pages.pages !== void 0 && recordPages2.pages !== void 0;
|
|
1420
|
+
if (!isNamed || !isWhole || problems.length > 0) {
|
|
1123
1421
|
return invalid(problems);
|
|
1124
1422
|
}
|
|
1125
1423
|
const description = {
|
|
@@ -1127,7 +1425,8 @@ function checkSiteDescription(input) {
|
|
|
1127
1425
|
title,
|
|
1128
1426
|
schema: schema.fields,
|
|
1129
1427
|
initialContent: initial.content,
|
|
1130
|
-
pages: pages.pages
|
|
1428
|
+
pages: pages.pages,
|
|
1429
|
+
...recordPages2.pages.length === 0 ? {} : { recordPages: recordPages2.pages }
|
|
1131
1430
|
};
|
|
1132
1431
|
return { status: "read", description };
|
|
1133
1432
|
}
|
|
@@ -1179,6 +1478,76 @@ function readPage(schema, input) {
|
|
|
1179
1478
|
const isSearchTexts = typeof searchTexts === "string" && isSearchTextsGroup(schema, searchTexts);
|
|
1180
1479
|
return isSearchTexts ? { path, title, searchTexts } : "invalid-search-texts";
|
|
1181
1480
|
}
|
|
1481
|
+
function checkRecordPages(schema, input) {
|
|
1482
|
+
if (input === void 0) return { pages: [], problems: [] };
|
|
1483
|
+
if (!Array.isArray(input)) {
|
|
1484
|
+
return { pages: void 0, problems: [{ code: "invalid-record-pages" }] };
|
|
1485
|
+
}
|
|
1486
|
+
const entries = input;
|
|
1487
|
+
const readings = entries.map((entry) => readRecordPage(schema, entry));
|
|
1488
|
+
const pageProblems = readings.flatMap(
|
|
1489
|
+
(reading, index) => typeof reading === "string" ? [{ code: "invalid-record-page", index, reason: reading }] : []
|
|
1490
|
+
);
|
|
1491
|
+
const pages = readings.filter((reading) => typeof reading !== "string");
|
|
1492
|
+
const problems = [...pageProblems, ...recordPageRepeats(pages)];
|
|
1493
|
+
return { pages: problems.length === 0 ? pages : void 0, problems };
|
|
1494
|
+
}
|
|
1495
|
+
function recordPageRepeats(pages) {
|
|
1496
|
+
const paths = pages.map((page) => page.path);
|
|
1497
|
+
const collections = pages.map((page) => page.collection);
|
|
1498
|
+
const repeatedPaths = paths.filter(
|
|
1499
|
+
(path, index) => paths.indexOf(path) !== index
|
|
1500
|
+
);
|
|
1501
|
+
const repeatedCollections = collections.filter(
|
|
1502
|
+
(collection2, index) => collections.indexOf(collection2) !== index
|
|
1503
|
+
);
|
|
1504
|
+
const pathProblems = [...new Set(repeatedPaths)].map(
|
|
1505
|
+
(path) => ({ code: "repeated-page-path", path })
|
|
1506
|
+
);
|
|
1507
|
+
const collectionProblems = [...new Set(repeatedCollections)].map(
|
|
1508
|
+
(collection2) => ({ code: "repeated-record-pages", collection: collection2 })
|
|
1509
|
+
);
|
|
1510
|
+
return [...pathProblems, ...collectionProblems];
|
|
1511
|
+
}
|
|
1512
|
+
function readRecordPage(schema, input) {
|
|
1513
|
+
if (!isJsonObject(input)) return "not-a-page";
|
|
1514
|
+
const { path, collection: collection2, searchTexts } = input;
|
|
1515
|
+
if (!isRecordPagePath(path)) return "invalid-path";
|
|
1516
|
+
if (typeof collection2 !== "string") return "unknown-collection";
|
|
1517
|
+
const field = collectionFieldAt(schema, collection2);
|
|
1518
|
+
if (field === void 0) return "unknown-collection";
|
|
1519
|
+
if (searchTexts === void 0) return { path, collection: collection2 };
|
|
1520
|
+
const isSearchTexts = typeof searchTexts === "string" && isSearchTextsGroup(field.item, searchTexts);
|
|
1521
|
+
return isSearchTexts ? { path, collection: collection2, searchTexts } : "invalid-search-texts";
|
|
1522
|
+
}
|
|
1523
|
+
function placementProblems(pages, recordPages2) {
|
|
1524
|
+
const misplaced = pages.filter(
|
|
1525
|
+
(page) => recordPageAt(recordPages2, page.path) !== void 0
|
|
1526
|
+
);
|
|
1527
|
+
return misplaced.map(
|
|
1528
|
+
(page) => ({ code: "page-among-record-pages", path: page.path })
|
|
1529
|
+
);
|
|
1530
|
+
}
|
|
1531
|
+
function addressProblems(schema, initialContent, recordPages2) {
|
|
1532
|
+
return recordPages2.flatMap((page) => {
|
|
1533
|
+
const found = collectionAt(schema, initialContent, page.collection);
|
|
1534
|
+
if (found === void 0) return [];
|
|
1535
|
+
const addresses = found.records.map(
|
|
1536
|
+
(record) => recordAddressOf(found.collection, record)
|
|
1537
|
+
);
|
|
1538
|
+
return addresses.flatMap(
|
|
1539
|
+
(_, index) => recordAddressProblems(page.collection, addresses, index)
|
|
1540
|
+
);
|
|
1541
|
+
});
|
|
1542
|
+
}
|
|
1543
|
+
function recordAddressProblems(collection2, addresses, index) {
|
|
1544
|
+
const address = addresses[index];
|
|
1545
|
+
if (address === void 0) {
|
|
1546
|
+
return [{ code: "record-without-address", collection: collection2, index }];
|
|
1547
|
+
}
|
|
1548
|
+
const isRepeated = addresses.indexOf(address) < index;
|
|
1549
|
+
return isRepeated ? [{ code: "repeated-record-address", collection: collection2, address }] : [];
|
|
1550
|
+
}
|
|
1182
1551
|
function isPagePath(path) {
|
|
1183
1552
|
return typeof path === "string" && (path === HOME_PAGE_PATH || PAGE_PATH.test(path));
|
|
1184
1553
|
}
|
|
@@ -1199,14 +1568,17 @@ export {
|
|
|
1199
1568
|
choices,
|
|
1200
1569
|
url,
|
|
1201
1570
|
time,
|
|
1571
|
+
slug,
|
|
1202
1572
|
reference,
|
|
1203
1573
|
references,
|
|
1204
1574
|
group,
|
|
1205
1575
|
collection,
|
|
1206
1576
|
defaultValue,
|
|
1207
1577
|
defaultContent,
|
|
1578
|
+
FIELD_PATH_SEPARATOR,
|
|
1208
1579
|
resolveFieldPath,
|
|
1209
1580
|
isJsonObject,
|
|
1581
|
+
isContentObject,
|
|
1210
1582
|
linkTargetOf,
|
|
1211
1583
|
safeHref,
|
|
1212
1584
|
hrefOf,
|
|
@@ -1221,7 +1593,12 @@ export {
|
|
|
1221
1593
|
newRecord,
|
|
1222
1594
|
withRecordIds,
|
|
1223
1595
|
collectionAt,
|
|
1596
|
+
collectionFieldAt,
|
|
1224
1597
|
findRecord,
|
|
1598
|
+
slugFieldOf,
|
|
1599
|
+
MAX_SLUG_LENGTH,
|
|
1600
|
+
isSlug,
|
|
1601
|
+
slugOf,
|
|
1225
1602
|
formatFieldPath,
|
|
1226
1603
|
countCharacters,
|
|
1227
1604
|
parseContent,
|
|
@@ -1235,11 +1612,20 @@ export {
|
|
|
1235
1612
|
contactsFields,
|
|
1236
1613
|
WEEKDAYS,
|
|
1237
1614
|
openingHoursField,
|
|
1615
|
+
productFields,
|
|
1238
1616
|
readFields,
|
|
1239
1617
|
checkFields,
|
|
1240
1618
|
SITE_CONFIG_FILE,
|
|
1241
1619
|
isSiteId,
|
|
1242
1620
|
readSiteConfig,
|
|
1621
|
+
RECORD_PLACEHOLDER,
|
|
1622
|
+
PAGE_PATH_SEPARATOR,
|
|
1623
|
+
recordPages,
|
|
1624
|
+
isRecordPagePath,
|
|
1625
|
+
recordAddressOf,
|
|
1626
|
+
recordPagePath,
|
|
1627
|
+
recordPageAt,
|
|
1628
|
+
recordAt,
|
|
1243
1629
|
SITE_DESCRIPTION_PATH,
|
|
1244
1630
|
HOME_PAGE_PATH,
|
|
1245
1631
|
readSiteDescription,
|
package/dist/cli.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
SITE_MODULE_FILE
|
|
4
|
+
} from "./chunk-QCVWHHJC.js";
|
|
2
5
|
import {
|
|
3
6
|
SITE_CONFIG_FILE,
|
|
4
7
|
isSiteId,
|
|
5
8
|
readSiteConfig
|
|
6
|
-
} from "./chunk-
|
|
7
|
-
import {
|
|
8
|
-
SITE_MODULE_FILE
|
|
9
|
-
} from "./chunk-QCVWHHJC.js";
|
|
9
|
+
} from "./chunk-UL2C2IB2.js";
|
|
10
10
|
|
|
11
11
|
// src/cli.ts
|
|
12
12
|
import process from "process";
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
OWN_PHOTOS_PATH
|
|
3
3
|
} from "./chunk-W2LIOR2C.js";
|
|
4
|
-
import {
|
|
5
|
-
SITE_CONFIG_FILE,
|
|
6
|
-
SITE_DESCRIPTION_PATH,
|
|
7
|
-
isJsonObject,
|
|
8
|
-
readSiteConfig
|
|
9
|
-
} from "./chunk-ZS32CW5F.js";
|
|
10
4
|
import {
|
|
11
5
|
PREVIEW_PATH,
|
|
12
6
|
SITE_MODULE_FILE,
|
|
@@ -14,7 +8,14 @@ import {
|
|
|
14
8
|
} from "./chunk-QCVWHHJC.js";
|
|
15
9
|
import {
|
|
16
10
|
isUploadedPhoto
|
|
17
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-OCA2WYK3.js";
|
|
12
|
+
import "./chunk-HFPZVDST.js";
|
|
13
|
+
import {
|
|
14
|
+
SITE_CONFIG_FILE,
|
|
15
|
+
SITE_DESCRIPTION_PATH,
|
|
16
|
+
isJsonObject,
|
|
17
|
+
readSiteConfig
|
|
18
|
+
} from "./chunk-UL2C2IB2.js";
|
|
18
19
|
|
|
19
20
|
// src/index.ts
|
|
20
21
|
import process from "process";
|