@tinacms/schema-tools 0.0.9 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.es.js +90 -41
- package/dist/index.js +90 -41
- package/dist/types/SchemaTypes.d.ts +46 -17
- package/dist/types/config.d.ts +40 -0
- package/dist/util/hasDuplicates.d.ts +7 -1
- package/dist/validate/properties.d.ts +1 -1
- package/dist/validate/schema.d.ts +2 -2
- package/package.json +2 -2
package/dist/index.es.js
CHANGED
|
@@ -7,6 +7,9 @@ function addNamespaceToSchema(maybeNode, namespace = []) {
|
|
|
7
7
|
if (typeof maybeNode === "boolean") {
|
|
8
8
|
return maybeNode;
|
|
9
9
|
}
|
|
10
|
+
if (typeof maybeNode === "function") {
|
|
11
|
+
return maybeNode;
|
|
12
|
+
}
|
|
10
13
|
const newNode = { ...maybeNode };
|
|
11
14
|
const keys = Object.keys(maybeNode);
|
|
12
15
|
Object.values(maybeNode).map((m, index) => {
|
|
@@ -102,12 +105,14 @@ const NAMER = {
|
|
|
102
105
|
return generateNamespacedFieldName(namespace, "ConnectionEdges");
|
|
103
106
|
}
|
|
104
107
|
};
|
|
105
|
-
function
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
108
|
+
function findDuplicates(array = []) {
|
|
109
|
+
const duplicates = [
|
|
110
|
+
...new Set(array.filter((item, index) => array.indexOf(item) !== index))
|
|
111
|
+
].map((x) => `"${x}"`);
|
|
112
|
+
if (duplicates.length) {
|
|
113
|
+
return duplicates.join(", ");
|
|
114
|
+
} else
|
|
115
|
+
return void 0;
|
|
111
116
|
}
|
|
112
117
|
class TinaSchema {
|
|
113
118
|
constructor(config) {
|
|
@@ -169,12 +174,7 @@ class TinaSchema {
|
|
|
169
174
|
};
|
|
170
175
|
this.getCollectionAndTemplateByFullPath = (filepath, templateName) => {
|
|
171
176
|
let template;
|
|
172
|
-
const collection = this.
|
|
173
|
-
return filepath.replace("\\", "/").startsWith(collection2.path);
|
|
174
|
-
});
|
|
175
|
-
if (!collection) {
|
|
176
|
-
throw new Error(`Unable to find collection for file at ${filepath}`);
|
|
177
|
-
}
|
|
177
|
+
const collection = this.getCollectionByFullPath(filepath);
|
|
178
178
|
const templates = this.getTemplatesForCollectable(collection);
|
|
179
179
|
if (templates.type === "union") {
|
|
180
180
|
if (templateName) {
|
|
@@ -374,6 +374,7 @@ const resolveField = ({ namespace, ...field }, schema) => {
|
|
|
374
374
|
key: templateName,
|
|
375
375
|
inline: template.inline,
|
|
376
376
|
name: templateName,
|
|
377
|
+
match: template.match,
|
|
377
378
|
fields: template.fields.map((field2) => resolveField(field2, schema)),
|
|
378
379
|
...extraFields2
|
|
379
380
|
};
|
|
@@ -437,7 +438,9 @@ const parseZodError = ({ zodError }) => {
|
|
|
437
438
|
const name = z.string({
|
|
438
439
|
required_error: "Name is required but not provided",
|
|
439
440
|
invalid_type_error: "Name must be a string"
|
|
440
|
-
})
|
|
441
|
+
}).refine((val) => val.match(/^[a-zA-Z0-9_]*$/) !== null, (val) => ({
|
|
442
|
+
message: `name, "${val}" must be alphanumeric and can only contain underscores`
|
|
443
|
+
}));
|
|
441
444
|
const TypeName = [
|
|
442
445
|
"string",
|
|
443
446
|
"boolean",
|
|
@@ -456,7 +459,7 @@ const nameProp = z.string({
|
|
|
456
459
|
}).superRefine((val, ctx) => {
|
|
457
460
|
if (val.includes(" "))
|
|
458
461
|
ctx.addIssue({
|
|
459
|
-
message:
|
|
462
|
+
message: `name "${val}" cannot contain spaces`,
|
|
460
463
|
code: z.ZodIssueCode.custom,
|
|
461
464
|
fatal: true
|
|
462
465
|
});
|
|
@@ -521,23 +524,42 @@ const TinaFieldZod = z.lazy(() => {
|
|
|
521
524
|
const TemplateTemp = z.object({
|
|
522
525
|
label: z.string(),
|
|
523
526
|
name: nameProp,
|
|
524
|
-
fields: z.array(TinaFieldZod)
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
527
|
+
fields: z.array(TinaFieldZod),
|
|
528
|
+
match: z.object({
|
|
529
|
+
start: z.string(),
|
|
530
|
+
end: z.string()
|
|
531
|
+
}).optional()
|
|
532
|
+
}).superRefine((val, ctx) => {
|
|
533
|
+
const dups = findDuplicates(val == null ? void 0 : val.fields.map((x) => x.name));
|
|
534
|
+
if (dups) {
|
|
535
|
+
ctx.addIssue({
|
|
536
|
+
code: z.ZodIssueCode.custom,
|
|
537
|
+
message: `Fields must have a unique name, duplicate field names: ${dups}`
|
|
538
|
+
});
|
|
539
|
+
}
|
|
530
540
|
});
|
|
531
541
|
const ObjectField = FieldWithList.extend({
|
|
532
542
|
type: z.literal("object", {
|
|
533
543
|
invalid_type_error: typeTypeError,
|
|
534
544
|
required_error: typeRequiredError
|
|
535
545
|
}),
|
|
536
|
-
fields: z.array(TinaFieldZod).min(1).optional().
|
|
537
|
-
|
|
546
|
+
fields: z.array(TinaFieldZod).min(1).optional().superRefine((val, ctx) => {
|
|
547
|
+
const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
|
|
548
|
+
if (dups) {
|
|
549
|
+
ctx.addIssue({
|
|
550
|
+
code: z.ZodIssueCode.custom,
|
|
551
|
+
message: `Fields must have a unique name, duplicate field names: ${dups}`
|
|
552
|
+
});
|
|
553
|
+
}
|
|
538
554
|
}),
|
|
539
|
-
templates: z.array(TemplateTemp).min(1).optional().
|
|
540
|
-
|
|
555
|
+
templates: z.array(TemplateTemp).min(1).optional().superRefine((val, ctx) => {
|
|
556
|
+
const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
|
|
557
|
+
if (dups) {
|
|
558
|
+
ctx.addIssue({
|
|
559
|
+
code: z.ZodIssueCode.custom,
|
|
560
|
+
message: `Templates must have a unique name, duplicate template names: ${dups}`
|
|
561
|
+
});
|
|
562
|
+
}
|
|
541
563
|
})
|
|
542
564
|
});
|
|
543
565
|
const RichTextField = FieldWithList.extend({
|
|
@@ -545,8 +567,14 @@ const TinaFieldZod = z.lazy(() => {
|
|
|
545
567
|
invalid_type_error: typeTypeError,
|
|
546
568
|
required_error: typeRequiredError
|
|
547
569
|
}),
|
|
548
|
-
templates: z.array(TemplateTemp).optional().
|
|
549
|
-
|
|
570
|
+
templates: z.array(TemplateTemp).optional().superRefine((val, ctx) => {
|
|
571
|
+
const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
|
|
572
|
+
if (dups) {
|
|
573
|
+
ctx.addIssue({
|
|
574
|
+
code: z.ZodIssueCode.custom,
|
|
575
|
+
message: `Templates must have a unique name, duplicate template names: ${dups}`
|
|
576
|
+
});
|
|
577
|
+
}
|
|
550
578
|
})
|
|
551
579
|
});
|
|
552
580
|
return z.discriminatedUnion("type", [
|
|
@@ -576,13 +604,17 @@ const TinaFieldZod = z.lazy(() => {
|
|
|
576
604
|
if (val.list) {
|
|
577
605
|
ctx.addIssue({
|
|
578
606
|
code: z.ZodIssueCode.custom,
|
|
579
|
-
message:
|
|
607
|
+
message: `Can not have \`list: true\` when using \`isTitle\`. Error in value
|
|
608
|
+
${JSON.stringify(val, null, 2)}
|
|
609
|
+
`
|
|
580
610
|
});
|
|
581
611
|
}
|
|
582
612
|
if (!val.required) {
|
|
583
613
|
ctx.addIssue({
|
|
584
614
|
code: z.ZodIssueCode.custom,
|
|
585
|
-
message:
|
|
615
|
+
message: `Must have { required: true } when using \`isTitle\` Error in value
|
|
616
|
+
${JSON.stringify(val, null, 2)}
|
|
617
|
+
`
|
|
586
618
|
});
|
|
587
619
|
}
|
|
588
620
|
}
|
|
@@ -633,11 +665,15 @@ const Template = z.object({
|
|
|
633
665
|
}),
|
|
634
666
|
name,
|
|
635
667
|
fields: z.array(TinaFieldZod)
|
|
636
|
-
}).
|
|
668
|
+
}).superRefine((val, ctx) => {
|
|
637
669
|
var _a;
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
670
|
+
const dups = findDuplicates((_a = val.fields) == null ? void 0 : _a.map((x) => x.name));
|
|
671
|
+
if (dups) {
|
|
672
|
+
ctx.addIssue({
|
|
673
|
+
code: z.ZodIssueCode.custom,
|
|
674
|
+
message: `Fields must have a unique name, duplicate field names: ${dups}`
|
|
675
|
+
});
|
|
676
|
+
}
|
|
641
677
|
});
|
|
642
678
|
const TinaCloudCollectionBase = z.object({
|
|
643
679
|
label: z.string().optional(),
|
|
@@ -645,16 +681,28 @@ const TinaCloudCollectionBase = z.object({
|
|
|
645
681
|
format: z.enum(FORMATS).optional()
|
|
646
682
|
});
|
|
647
683
|
const TinaCloudCollection = TinaCloudCollectionBase.extend({
|
|
648
|
-
fields: z.array(TinaFieldZod).min(1).optional().
|
|
649
|
-
|
|
684
|
+
fields: z.array(TinaFieldZod).min(1).optional().superRefine((val, ctx) => {
|
|
685
|
+
const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
|
|
686
|
+
if (dups) {
|
|
687
|
+
ctx.addIssue({
|
|
688
|
+
code: z.ZodIssueCode.custom,
|
|
689
|
+
message: `Fields must have a unique name, duplicate field names: ${dups}`
|
|
690
|
+
});
|
|
691
|
+
}
|
|
650
692
|
}).refine((val) => {
|
|
651
693
|
const arr = (val == null ? void 0 : val.filter((x) => x.type === "string" && x.isTitle)) || [];
|
|
652
694
|
return arr.length < 2;
|
|
653
695
|
}, {
|
|
654
696
|
message: "Fields can only have one use of `isTitle`"
|
|
655
697
|
}),
|
|
656
|
-
templates: z.array(Template).min(1).optional().
|
|
657
|
-
|
|
698
|
+
templates: z.array(Template).min(1).optional().superRefine((val, ctx) => {
|
|
699
|
+
const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
|
|
700
|
+
if (dups) {
|
|
701
|
+
ctx.addIssue({
|
|
702
|
+
code: z.ZodIssueCode.custom,
|
|
703
|
+
message: `Templates must have a unique name, duplicate template names: ${dups}`
|
|
704
|
+
});
|
|
705
|
+
}
|
|
658
706
|
})
|
|
659
707
|
}).refine((val) => {
|
|
660
708
|
let isValid = Boolean(val == null ? void 0 : val.templates) || Boolean(val == null ? void 0 : val.fields);
|
|
@@ -669,20 +717,21 @@ const TinaCloudSchemaZod = z.object({
|
|
|
669
717
|
collections: z.array(TinaCloudCollection),
|
|
670
718
|
config: tinaConfigZod.optional()
|
|
671
719
|
}).superRefine((val, ctx) => {
|
|
672
|
-
var _a, _b;
|
|
673
|
-
|
|
720
|
+
var _a, _b, _c;
|
|
721
|
+
const dups = findDuplicates((_a = val.collections) == null ? void 0 : _a.map((x) => x.name));
|
|
722
|
+
if (dups) {
|
|
674
723
|
ctx.addIssue({
|
|
675
724
|
code: z.ZodIssueCode.custom,
|
|
676
|
-
message:
|
|
725
|
+
message: `${dups} are duplicate names in your collections. Collection names must be unique.`,
|
|
677
726
|
fatal: true
|
|
678
727
|
});
|
|
679
728
|
}
|
|
680
|
-
(
|
|
729
|
+
(_b = val == null ? void 0 : val.collections) == null ? void 0 : _b.map((x) => {
|
|
681
730
|
if (!x.format) {
|
|
682
731
|
console.warn(`No format provided for collection ${x.name}, defaulting to .md`);
|
|
683
732
|
}
|
|
684
733
|
});
|
|
685
|
-
const media = (
|
|
734
|
+
const media = (_c = val == null ? void 0 : val.config) == null ? void 0 : _c.media;
|
|
686
735
|
if (media && media.tina && media.loadCustomStore) {
|
|
687
736
|
ctx.addIssue({
|
|
688
737
|
code: z.ZodIssueCode.custom,
|
package/dist/index.js
CHANGED
|
@@ -34,6 +34,9 @@
|
|
|
34
34
|
if (typeof maybeNode === "boolean") {
|
|
35
35
|
return maybeNode;
|
|
36
36
|
}
|
|
37
|
+
if (typeof maybeNode === "function") {
|
|
38
|
+
return maybeNode;
|
|
39
|
+
}
|
|
37
40
|
const newNode = { ...maybeNode };
|
|
38
41
|
const keys = Object.keys(maybeNode);
|
|
39
42
|
Object.values(maybeNode).map((m, index) => {
|
|
@@ -129,12 +132,14 @@
|
|
|
129
132
|
return generateNamespacedFieldName(namespace, "ConnectionEdges");
|
|
130
133
|
}
|
|
131
134
|
};
|
|
132
|
-
function
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
135
|
+
function findDuplicates(array = []) {
|
|
136
|
+
const duplicates = [
|
|
137
|
+
...new Set(array.filter((item, index) => array.indexOf(item) !== index))
|
|
138
|
+
].map((x) => `"${x}"`);
|
|
139
|
+
if (duplicates.length) {
|
|
140
|
+
return duplicates.join(", ");
|
|
141
|
+
} else
|
|
142
|
+
return void 0;
|
|
138
143
|
}
|
|
139
144
|
class TinaSchema {
|
|
140
145
|
constructor(config) {
|
|
@@ -196,12 +201,7 @@
|
|
|
196
201
|
};
|
|
197
202
|
this.getCollectionAndTemplateByFullPath = (filepath, templateName) => {
|
|
198
203
|
let template;
|
|
199
|
-
const collection = this.
|
|
200
|
-
return filepath.replace("\\", "/").startsWith(collection2.path);
|
|
201
|
-
});
|
|
202
|
-
if (!collection) {
|
|
203
|
-
throw new Error(`Unable to find collection for file at ${filepath}`);
|
|
204
|
-
}
|
|
204
|
+
const collection = this.getCollectionByFullPath(filepath);
|
|
205
205
|
const templates = this.getTemplatesForCollectable(collection);
|
|
206
206
|
if (templates.type === "union") {
|
|
207
207
|
if (templateName) {
|
|
@@ -401,6 +401,7 @@
|
|
|
401
401
|
key: templateName,
|
|
402
402
|
inline: template.inline,
|
|
403
403
|
name: templateName,
|
|
404
|
+
match: template.match,
|
|
404
405
|
fields: template.fields.map((field2) => resolveField(field2, schema)),
|
|
405
406
|
...extraFields2
|
|
406
407
|
};
|
|
@@ -464,7 +465,9 @@
|
|
|
464
465
|
const name = z.z.string({
|
|
465
466
|
required_error: "Name is required but not provided",
|
|
466
467
|
invalid_type_error: "Name must be a string"
|
|
467
|
-
})
|
|
468
|
+
}).refine((val) => val.match(/^[a-zA-Z0-9_]*$/) !== null, (val) => ({
|
|
469
|
+
message: `name, "${val}" must be alphanumeric and can only contain underscores`
|
|
470
|
+
}));
|
|
468
471
|
const TypeName = [
|
|
469
472
|
"string",
|
|
470
473
|
"boolean",
|
|
@@ -483,7 +486,7 @@
|
|
|
483
486
|
}).superRefine((val, ctx) => {
|
|
484
487
|
if (val.includes(" "))
|
|
485
488
|
ctx.addIssue({
|
|
486
|
-
message:
|
|
489
|
+
message: `name "${val}" cannot contain spaces`,
|
|
487
490
|
code: z.z.ZodIssueCode.custom,
|
|
488
491
|
fatal: true
|
|
489
492
|
});
|
|
@@ -548,23 +551,42 @@
|
|
|
548
551
|
const TemplateTemp = z.z.object({
|
|
549
552
|
label: z.z.string(),
|
|
550
553
|
name: nameProp,
|
|
551
|
-
fields: z.z.array(TinaFieldZod)
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
554
|
+
fields: z.z.array(TinaFieldZod),
|
|
555
|
+
match: z.z.object({
|
|
556
|
+
start: z.z.string(),
|
|
557
|
+
end: z.z.string()
|
|
558
|
+
}).optional()
|
|
559
|
+
}).superRefine((val, ctx) => {
|
|
560
|
+
const dups = findDuplicates(val == null ? void 0 : val.fields.map((x) => x.name));
|
|
561
|
+
if (dups) {
|
|
562
|
+
ctx.addIssue({
|
|
563
|
+
code: z.z.ZodIssueCode.custom,
|
|
564
|
+
message: `Fields must have a unique name, duplicate field names: ${dups}`
|
|
565
|
+
});
|
|
566
|
+
}
|
|
557
567
|
});
|
|
558
568
|
const ObjectField = FieldWithList.extend({
|
|
559
569
|
type: z.z.literal("object", {
|
|
560
570
|
invalid_type_error: typeTypeError,
|
|
561
571
|
required_error: typeRequiredError
|
|
562
572
|
}),
|
|
563
|
-
fields: z.z.array(TinaFieldZod).min(1).optional().
|
|
564
|
-
|
|
573
|
+
fields: z.z.array(TinaFieldZod).min(1).optional().superRefine((val, ctx) => {
|
|
574
|
+
const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
|
|
575
|
+
if (dups) {
|
|
576
|
+
ctx.addIssue({
|
|
577
|
+
code: z.z.ZodIssueCode.custom,
|
|
578
|
+
message: `Fields must have a unique name, duplicate field names: ${dups}`
|
|
579
|
+
});
|
|
580
|
+
}
|
|
565
581
|
}),
|
|
566
|
-
templates: z.z.array(TemplateTemp).min(1).optional().
|
|
567
|
-
|
|
582
|
+
templates: z.z.array(TemplateTemp).min(1).optional().superRefine((val, ctx) => {
|
|
583
|
+
const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
|
|
584
|
+
if (dups) {
|
|
585
|
+
ctx.addIssue({
|
|
586
|
+
code: z.z.ZodIssueCode.custom,
|
|
587
|
+
message: `Templates must have a unique name, duplicate template names: ${dups}`
|
|
588
|
+
});
|
|
589
|
+
}
|
|
568
590
|
})
|
|
569
591
|
});
|
|
570
592
|
const RichTextField = FieldWithList.extend({
|
|
@@ -572,8 +594,14 @@
|
|
|
572
594
|
invalid_type_error: typeTypeError,
|
|
573
595
|
required_error: typeRequiredError
|
|
574
596
|
}),
|
|
575
|
-
templates: z.z.array(TemplateTemp).optional().
|
|
576
|
-
|
|
597
|
+
templates: z.z.array(TemplateTemp).optional().superRefine((val, ctx) => {
|
|
598
|
+
const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
|
|
599
|
+
if (dups) {
|
|
600
|
+
ctx.addIssue({
|
|
601
|
+
code: z.z.ZodIssueCode.custom,
|
|
602
|
+
message: `Templates must have a unique name, duplicate template names: ${dups}`
|
|
603
|
+
});
|
|
604
|
+
}
|
|
577
605
|
})
|
|
578
606
|
});
|
|
579
607
|
return z.z.discriminatedUnion("type", [
|
|
@@ -603,13 +631,17 @@
|
|
|
603
631
|
if (val.list) {
|
|
604
632
|
ctx.addIssue({
|
|
605
633
|
code: z.z.ZodIssueCode.custom,
|
|
606
|
-
message:
|
|
634
|
+
message: `Can not have \`list: true\` when using \`isTitle\`. Error in value
|
|
635
|
+
${JSON.stringify(val, null, 2)}
|
|
636
|
+
`
|
|
607
637
|
});
|
|
608
638
|
}
|
|
609
639
|
if (!val.required) {
|
|
610
640
|
ctx.addIssue({
|
|
611
641
|
code: z.z.ZodIssueCode.custom,
|
|
612
|
-
message:
|
|
642
|
+
message: `Must have { required: true } when using \`isTitle\` Error in value
|
|
643
|
+
${JSON.stringify(val, null, 2)}
|
|
644
|
+
`
|
|
613
645
|
});
|
|
614
646
|
}
|
|
615
647
|
}
|
|
@@ -660,11 +692,15 @@
|
|
|
660
692
|
}),
|
|
661
693
|
name,
|
|
662
694
|
fields: z.z.array(TinaFieldZod)
|
|
663
|
-
}).
|
|
695
|
+
}).superRefine((val, ctx) => {
|
|
664
696
|
var _a;
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
697
|
+
const dups = findDuplicates((_a = val.fields) == null ? void 0 : _a.map((x) => x.name));
|
|
698
|
+
if (dups) {
|
|
699
|
+
ctx.addIssue({
|
|
700
|
+
code: z.z.ZodIssueCode.custom,
|
|
701
|
+
message: `Fields must have a unique name, duplicate field names: ${dups}`
|
|
702
|
+
});
|
|
703
|
+
}
|
|
668
704
|
});
|
|
669
705
|
const TinaCloudCollectionBase = z.z.object({
|
|
670
706
|
label: z.z.string().optional(),
|
|
@@ -672,16 +708,28 @@
|
|
|
672
708
|
format: z.z.enum(FORMATS).optional()
|
|
673
709
|
});
|
|
674
710
|
const TinaCloudCollection = TinaCloudCollectionBase.extend({
|
|
675
|
-
fields: z.z.array(TinaFieldZod).min(1).optional().
|
|
676
|
-
|
|
711
|
+
fields: z.z.array(TinaFieldZod).min(1).optional().superRefine((val, ctx) => {
|
|
712
|
+
const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
|
|
713
|
+
if (dups) {
|
|
714
|
+
ctx.addIssue({
|
|
715
|
+
code: z.z.ZodIssueCode.custom,
|
|
716
|
+
message: `Fields must have a unique name, duplicate field names: ${dups}`
|
|
717
|
+
});
|
|
718
|
+
}
|
|
677
719
|
}).refine((val) => {
|
|
678
720
|
const arr = (val == null ? void 0 : val.filter((x) => x.type === "string" && x.isTitle)) || [];
|
|
679
721
|
return arr.length < 2;
|
|
680
722
|
}, {
|
|
681
723
|
message: "Fields can only have one use of `isTitle`"
|
|
682
724
|
}),
|
|
683
|
-
templates: z.z.array(Template).min(1).optional().
|
|
684
|
-
|
|
725
|
+
templates: z.z.array(Template).min(1).optional().superRefine((val, ctx) => {
|
|
726
|
+
const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
|
|
727
|
+
if (dups) {
|
|
728
|
+
ctx.addIssue({
|
|
729
|
+
code: z.z.ZodIssueCode.custom,
|
|
730
|
+
message: `Templates must have a unique name, duplicate template names: ${dups}`
|
|
731
|
+
});
|
|
732
|
+
}
|
|
685
733
|
})
|
|
686
734
|
}).refine((val) => {
|
|
687
735
|
let isValid = Boolean(val == null ? void 0 : val.templates) || Boolean(val == null ? void 0 : val.fields);
|
|
@@ -696,20 +744,21 @@
|
|
|
696
744
|
collections: z.z.array(TinaCloudCollection),
|
|
697
745
|
config: tinaConfigZod.optional()
|
|
698
746
|
}).superRefine((val, ctx) => {
|
|
699
|
-
var _a, _b;
|
|
700
|
-
|
|
747
|
+
var _a, _b, _c;
|
|
748
|
+
const dups = findDuplicates((_a = val.collections) == null ? void 0 : _a.map((x) => x.name));
|
|
749
|
+
if (dups) {
|
|
701
750
|
ctx.addIssue({
|
|
702
751
|
code: z.z.ZodIssueCode.custom,
|
|
703
|
-
message:
|
|
752
|
+
message: `${dups} are duplicate names in your collections. Collection names must be unique.`,
|
|
704
753
|
fatal: true
|
|
705
754
|
});
|
|
706
755
|
}
|
|
707
|
-
(
|
|
756
|
+
(_b = val == null ? void 0 : val.collections) == null ? void 0 : _b.map((x) => {
|
|
708
757
|
if (!x.format) {
|
|
709
758
|
console.warn(`No format provided for collection ${x.name}, defaulting to .md`);
|
|
710
759
|
}
|
|
711
760
|
});
|
|
712
|
-
const media = (
|
|
761
|
+
const media = (_c = val == null ? void 0 : val.config) == null ? void 0 : _c.media;
|
|
713
762
|
if (media && media.tina && media.loadCustomStore) {
|
|
714
763
|
ctx.addIssue({
|
|
715
764
|
code: z.z.ZodIssueCode.custom,
|
|
@@ -10,8 +10,9 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
10
10
|
See the License for the specific language governing permissions and
|
|
11
11
|
limitations under the License.
|
|
12
12
|
*/
|
|
13
|
-
import { TinaSchema } from '../schema';
|
|
14
13
|
import type { FC } from 'react';
|
|
14
|
+
import { TinaSchema } from '../schema';
|
|
15
|
+
import type { TinaCloudSchemaConfig } from './config';
|
|
15
16
|
export declare type UIField<F extends UIField = any, Shape = any> = {
|
|
16
17
|
label?: string;
|
|
17
18
|
description?: string;
|
|
@@ -21,21 +22,6 @@ export declare type UIField<F extends UIField = any, Shape = any> = {
|
|
|
21
22
|
validate?(value: Shape, allValues: any, meta: any, field: UIField<F, Shape>): string | object | undefined | void;
|
|
22
23
|
defaultValue?: Shape;
|
|
23
24
|
};
|
|
24
|
-
export interface TinaCloudSchemaConfig<Store = any> {
|
|
25
|
-
client?: {
|
|
26
|
-
referenceDepth?: number;
|
|
27
|
-
};
|
|
28
|
-
clientId: string;
|
|
29
|
-
branch: string;
|
|
30
|
-
token: string;
|
|
31
|
-
media?: {
|
|
32
|
-
loadCustomStore?: () => Promise<Store>;
|
|
33
|
-
tina?: {
|
|
34
|
-
publicFolder: string;
|
|
35
|
-
mediaRoot: string;
|
|
36
|
-
};
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
25
|
export interface TinaCloudSchema<WithNamespace extends boolean, Store = any> {
|
|
40
26
|
templates?: GlobalTemplate<WithNamespace>[];
|
|
41
27
|
collections: TinaCloudCollection<WithNamespace>[];
|
|
@@ -58,11 +44,46 @@ export declare type TinaCloudCollection<WithNamespace extends boolean> = Collect
|
|
|
58
44
|
export declare type TinaCloudCollectionBase = TinaCloudCollection<false>;
|
|
59
45
|
export declare type TinaCloudCollectionEnriched = TinaCloudCollection<true>;
|
|
60
46
|
declare type FormatType = 'json' | 'md' | 'markdown' | 'mdx';
|
|
47
|
+
declare type Document = {
|
|
48
|
+
_sys: {
|
|
49
|
+
title?: string;
|
|
50
|
+
template: string;
|
|
51
|
+
breadcrumbs: string[];
|
|
52
|
+
path: string;
|
|
53
|
+
basename: string;
|
|
54
|
+
relativePath: string;
|
|
55
|
+
filename: string;
|
|
56
|
+
extension: string;
|
|
57
|
+
};
|
|
58
|
+
};
|
|
61
59
|
interface BaseCollection {
|
|
62
60
|
label?: string;
|
|
63
61
|
name: string;
|
|
64
62
|
path: string;
|
|
65
63
|
format?: FormatType;
|
|
64
|
+
ui?: {
|
|
65
|
+
/**
|
|
66
|
+
* Forms for this collection will be editable from the global sidebar rather than the form panel
|
|
67
|
+
*/
|
|
68
|
+
global?: boolean | {
|
|
69
|
+
icon?: any;
|
|
70
|
+
layout: 'fullscreen' | 'popup';
|
|
71
|
+
};
|
|
72
|
+
/**
|
|
73
|
+
* Provide the path that your document is viewable on your site
|
|
74
|
+
*
|
|
75
|
+
* eg:
|
|
76
|
+
* ```ts
|
|
77
|
+
* router: ({ document }) => {
|
|
78
|
+
* return `blog-posts/${document._sys.filename}`;
|
|
79
|
+
* }
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
router?: (args: {
|
|
83
|
+
document: Document;
|
|
84
|
+
collection: TinaCloudCollection<true>;
|
|
85
|
+
}) => string | undefined;
|
|
86
|
+
};
|
|
66
87
|
match?: string;
|
|
67
88
|
}
|
|
68
89
|
declare type CollectionTemplates<WithNamespace extends boolean> = WithNamespace extends true ? CollectionTemplatesWithNamespace<WithNamespace> : CollectionTemplatesInner<WithNamespace>;
|
|
@@ -323,6 +344,10 @@ export declare type Template<WithNamespace extends boolean> = WithNamespace exte
|
|
|
323
344
|
label: string;
|
|
324
345
|
name: string;
|
|
325
346
|
fields: TinaFieldInner<WithNamespace>[];
|
|
347
|
+
match?: {
|
|
348
|
+
start: string;
|
|
349
|
+
end: string;
|
|
350
|
+
};
|
|
326
351
|
ui?: object | (UIField<any, any> & {
|
|
327
352
|
previewSrc: string;
|
|
328
353
|
});
|
|
@@ -334,6 +359,10 @@ export declare type Template<WithNamespace extends boolean> = WithNamespace exte
|
|
|
334
359
|
previewSrc: string;
|
|
335
360
|
});
|
|
336
361
|
fields: TinaFieldInner<WithNamespace>[];
|
|
362
|
+
match?: {
|
|
363
|
+
start: string;
|
|
364
|
+
end: string;
|
|
365
|
+
};
|
|
337
366
|
};
|
|
338
367
|
export declare type CollectionTemplateableUnion = {
|
|
339
368
|
namespace: string[];
|
|
@@ -366,4 +395,4 @@ export declare type ResolveFormArgs = {
|
|
|
366
395
|
template: Templateable;
|
|
367
396
|
schema: TinaSchema;
|
|
368
397
|
};
|
|
369
|
-
export
|
|
398
|
+
export * from './config';
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
Copyright 2021 Forestry.io Holdings, Inc.
|
|
3
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
you may not use this file except in compliance with the License.
|
|
5
|
+
You may obtain a copy of the License at
|
|
6
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
7
|
+
Unless required by applicable law or agreed to in writing, software
|
|
8
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
9
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
10
|
+
See the License for the specific language governing permissions and
|
|
11
|
+
limitations under the License.
|
|
12
|
+
*/
|
|
13
|
+
export interface TinaCloudSchemaConfig<Store = any> {
|
|
14
|
+
client?: {
|
|
15
|
+
referenceDepth?: number;
|
|
16
|
+
};
|
|
17
|
+
build?: {
|
|
18
|
+
publicFolder: string;
|
|
19
|
+
outputFolder: string;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* The base branch to pull content from. Note that this is ignored for local development
|
|
23
|
+
*/
|
|
24
|
+
branch?: string;
|
|
25
|
+
/**
|
|
26
|
+
* Your clientId from app.tina.io
|
|
27
|
+
*/
|
|
28
|
+
clientId?: string;
|
|
29
|
+
/**
|
|
30
|
+
* Your read only token from app.tina.io
|
|
31
|
+
*/
|
|
32
|
+
token?: string;
|
|
33
|
+
media?: {
|
|
34
|
+
loadCustomStore?: () => Promise<Store>;
|
|
35
|
+
tina?: {
|
|
36
|
+
publicFolder: string;
|
|
37
|
+
mediaRoot: string;
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
}
|
|
@@ -10,4 +10,10 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
10
10
|
See the License for the specific language governing permissions and
|
|
11
11
|
limitations under the License.
|
|
12
12
|
*/
|
|
13
|
-
export declare function hasDuplicates<T = any>(array
|
|
13
|
+
export declare function hasDuplicates<T = any>(array?: T[]): boolean;
|
|
14
|
+
/**
|
|
15
|
+
*
|
|
16
|
+
* @param array
|
|
17
|
+
* @returns False if the array is undefined or has no duplicates.
|
|
18
|
+
*/
|
|
19
|
+
export declare function findDuplicates<T = any>(array?: T[] | undefined): undefined | string;
|
|
@@ -14,13 +14,13 @@ import { z } from 'zod';
|
|
|
14
14
|
export declare const TinaCloudSchemaZod: z.ZodEffects<z.ZodObject<{
|
|
15
15
|
collections: z.ZodArray<z.ZodEffects<z.ZodObject<z.extendShape<{
|
|
16
16
|
label: z.ZodOptional<z.ZodString>;
|
|
17
|
-
name: z.ZodString
|
|
17
|
+
name: z.ZodEffects<z.ZodString, string, string>;
|
|
18
18
|
format: z.ZodOptional<z.ZodEnum<["json", "md", "markdown", "mdx"]>>;
|
|
19
19
|
}, {
|
|
20
20
|
fields: z.ZodEffects<z.ZodEffects<z.ZodOptional<z.ZodArray<z.ZodType<import("..").TinaFieldInner<false>, z.ZodTypeDef, import("..").TinaFieldInner<false>>, "many">>, import("..").TinaFieldInner<false>[], import("..").TinaFieldInner<false>[]>, import("..").TinaFieldInner<false>[], import("..").TinaFieldInner<false>[]>;
|
|
21
21
|
templates: z.ZodEffects<z.ZodOptional<z.ZodArray<z.ZodEffects<z.ZodObject<{
|
|
22
22
|
label: z.ZodString;
|
|
23
|
-
name: z.ZodString
|
|
23
|
+
name: z.ZodEffects<z.ZodString, string, string>;
|
|
24
24
|
fields: z.ZodArray<z.ZodType<import("..").TinaFieldInner<false>, z.ZodTypeDef, import("..").TinaFieldInner<false>>, "many">;
|
|
25
25
|
}, "strip", z.ZodTypeAny, {
|
|
26
26
|
name?: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tinacms/schema-tools",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"module": "./dist/index.es.js",
|
|
6
6
|
"exports": {
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
]
|
|
24
24
|
},
|
|
25
25
|
"devDependencies": {
|
|
26
|
-
"@tinacms/scripts": "0.
|
|
26
|
+
"@tinacms/scripts": "0.51.1",
|
|
27
27
|
"@types/yup": "^0.29.10",
|
|
28
28
|
"jest": "^27.0.6",
|
|
29
29
|
"react": "17.0.2",
|