@tinacms/schema-tools 1.3.2 → 1.3.4

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 CHANGED
@@ -200,14 +200,6 @@ class TinaSchema {
200
200
  this.getCollections = () => {
201
201
  return this.schema.collections.map((collection) => this.getCollection(collection.name)) || [];
202
202
  };
203
- this.getGlobalTemplate = (templateName) => {
204
- var _a;
205
- const globalTemplate = (_a = this.schema.templates) == null ? void 0 : _a.find((template) => template.name === templateName);
206
- if (!globalTemplate) {
207
- throw new Error(`Expected to find global template of name ${templateName}`);
208
- }
209
- return globalTemplate;
210
- };
211
203
  this.getCollectionByFullPath = (filepath) => {
212
204
  const possibleCollections = this.getCollections().filter((collection) => {
213
205
  return filepath.replace(/\\/g, "/").startsWith(collection.path.replace(/\/?$/, "/"));
@@ -365,11 +357,8 @@ class TinaSchema {
365
357
  };
366
358
  this.getTemplatesForCollectable = (collection) => {
367
359
  let extraFields = [];
368
- if (collection.references) {
369
- extraFields = collection.references;
370
- }
371
360
  if (collection.fields) {
372
- const template = typeof collection.fields === "string" ? this.getGlobalTemplate(collection.fields) : collection;
361
+ const template = collection;
373
362
  if (typeof template.fields === "string" || typeof template.fields === "undefined") {
374
363
  throw new Error("Exptected template to have fields but none were found");
375
364
  }
@@ -387,7 +376,7 @@ class TinaSchema {
387
376
  namespace: collection.namespace,
388
377
  type: "union",
389
378
  templates: collection.templates.map((templateOrTemplateString) => {
390
- const template = typeof templateOrTemplateString === "string" ? this.getGlobalTemplate(templateOrTemplateString) : templateOrTemplateString;
379
+ const template = templateOrTemplateString;
391
380
  return {
392
381
  ...template,
393
382
  fields: [...template.fields, ...extraFields]
@@ -404,7 +393,6 @@ class TinaSchema {
404
393
  }
405
394
  const resolveField = (field, schema) => {
406
395
  var _a;
407
- field.parentTypename = NAMER.dataTypeName(field.namespace.filter((_, i) => i < field.namespace.length - 1));
408
396
  const extraFields = field.ui || {};
409
397
  switch (field.type) {
410
398
  case "number":
@@ -426,6 +414,16 @@ const resolveField = (field, schema) => {
426
414
  ...extraFields
427
415
  };
428
416
  case "image":
417
+ if (field.list) {
418
+ return {
419
+ component: "list",
420
+ field: {
421
+ component: "image"
422
+ },
423
+ ...field,
424
+ ...extraFields
425
+ };
426
+ }
429
427
  return {
430
428
  component: "image",
431
429
  clearable: true,
@@ -586,9 +584,24 @@ const parseZodError = ({ zodError }) => {
586
584
  const name = z.string({
587
585
  required_error: "Name is required but not provided",
588
586
  invalid_type_error: "Name must be a string"
589
- }).refine((val) => val.match(/^[a-zA-Z0-9_]*$/) !== null, (val) => ({
590
- message: `name, "${val}" must be alphanumeric and can only contain underscores`
591
- }));
587
+ }).superRefine((val, ctx) => {
588
+ if (val.match(/^[a-zA-Z0-9_]*$/) === null) {
589
+ ctx.addIssue({
590
+ code: "custom",
591
+ message: `name, "${val}" must be alphanumeric and can only contain underscores. (No spaces, dashes, special characters, etc.)
592
+ If you only want to display this value in the CMS UI, you can use the label property to customize it.
593
+
594
+ If you need to use this value in your content you can use the \`nameOverride\` property to customize the value. For example:
595
+ \`\`\`
596
+ {
597
+ "name": ${val.replace(/[^a-zA-Z0-9]/g, "_")},
598
+ "nameOverride": ${val},
599
+ // ...
600
+ }
601
+ \`\`\``
602
+ });
603
+ }
604
+ });
592
605
  const TypeName = [
593
606
  "string",
594
607
  "boolean",
@@ -601,17 +614,6 @@ const TypeName = [
601
614
  ];
602
615
  const typeTypeError = `type must be one of ${TypeName.join(", ")}`;
603
616
  const typeRequiredError = `type is required and must be one of ${TypeName.join(", ")}`;
604
- const nameProp = z.string({
605
- required_error: "name must be provided",
606
- invalid_type_error: "name must be a sting"
607
- }).superRefine((val, ctx) => {
608
- if (val.includes(" "))
609
- ctx.addIssue({
610
- message: `name "${val}" cannot contain spaces`,
611
- code: z.ZodIssueCode.custom,
612
- fatal: true
613
- });
614
- });
615
617
  const Option = z.union([
616
618
  z.string(),
617
619
  z.object({ label: z.string(), value: z.string() }),
@@ -624,7 +626,7 @@ const Option = z.union([
624
626
  }
625
627
  });
626
628
  const TinaField = z.object({
627
- name: nameProp,
629
+ name,
628
630
  label: z.string().or(z.boolean()).optional(),
629
631
  description: z.string().optional(),
630
632
  required: z.boolean().optional()
@@ -675,7 +677,7 @@ const ReferenceField = FieldWithList.extend({
675
677
  const TinaFieldZod = z.lazy(() => {
676
678
  const TemplateTemp = z.object({
677
679
  label: z.string().optional(),
678
- name: nameProp,
680
+ name,
679
681
  fields: z.array(TinaFieldZod),
680
682
  match: z.object({
681
683
  start: z.string(),
@@ -836,7 +838,7 @@ const Template = z.object({
836
838
  });
837
839
  }
838
840
  });
839
- const TinaCloudCollectionBase = z.object({
841
+ const CollectionBaseSchema = z.object({
840
842
  label: z.string().optional(),
841
843
  name: name.superRefine((val, ctx) => {
842
844
  if (val === "relativePath") {
@@ -846,9 +848,10 @@ const TinaCloudCollectionBase = z.object({
846
848
  });
847
849
  }
848
850
  }),
851
+ path: z.string().transform((val) => val.replace(/^\/|\/$/g, "")),
849
852
  format: z.enum(FORMATS).optional()
850
853
  });
851
- const TinaCloudCollection = TinaCloudCollectionBase.extend({
854
+ const TinaCloudCollection = CollectionBaseSchema.extend({
852
855
  fields: z.array(TinaFieldZod).min(1).optional().superRefine((val, ctx) => {
853
856
  const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
854
857
  if (dups) {
@@ -910,9 +913,7 @@ class TinaSchemaValidationError extends Error {
910
913
  this.name = "TinaSchemaValidationError";
911
914
  }
912
915
  }
913
- const validateSchema = ({
914
- schema
915
- }) => {
916
+ const validateSchema = ({ schema }) => {
916
917
  try {
917
918
  TinaCloudSchemaZod.parse(schema);
918
919
  } catch (e) {
package/dist/index.js CHANGED
@@ -227,14 +227,6 @@
227
227
  this.getCollections = () => {
228
228
  return this.schema.collections.map((collection) => this.getCollection(collection.name)) || [];
229
229
  };
230
- this.getGlobalTemplate = (templateName) => {
231
- var _a;
232
- const globalTemplate = (_a = this.schema.templates) == null ? void 0 : _a.find((template) => template.name === templateName);
233
- if (!globalTemplate) {
234
- throw new Error(`Expected to find global template of name ${templateName}`);
235
- }
236
- return globalTemplate;
237
- };
238
230
  this.getCollectionByFullPath = (filepath) => {
239
231
  const possibleCollections = this.getCollections().filter((collection) => {
240
232
  return filepath.replace(/\\/g, "/").startsWith(collection.path.replace(/\/?$/, "/"));
@@ -392,11 +384,8 @@
392
384
  };
393
385
  this.getTemplatesForCollectable = (collection) => {
394
386
  let extraFields = [];
395
- if (collection.references) {
396
- extraFields = collection.references;
397
- }
398
387
  if (collection.fields) {
399
- const template = typeof collection.fields === "string" ? this.getGlobalTemplate(collection.fields) : collection;
388
+ const template = collection;
400
389
  if (typeof template.fields === "string" || typeof template.fields === "undefined") {
401
390
  throw new Error("Exptected template to have fields but none were found");
402
391
  }
@@ -414,7 +403,7 @@
414
403
  namespace: collection.namespace,
415
404
  type: "union",
416
405
  templates: collection.templates.map((templateOrTemplateString) => {
417
- const template = typeof templateOrTemplateString === "string" ? this.getGlobalTemplate(templateOrTemplateString) : templateOrTemplateString;
406
+ const template = templateOrTemplateString;
418
407
  return {
419
408
  ...template,
420
409
  fields: [...template.fields, ...extraFields]
@@ -431,7 +420,6 @@
431
420
  }
432
421
  const resolveField = (field, schema) => {
433
422
  var _a;
434
- field.parentTypename = NAMER.dataTypeName(field.namespace.filter((_, i) => i < field.namespace.length - 1));
435
423
  const extraFields = field.ui || {};
436
424
  switch (field.type) {
437
425
  case "number":
@@ -453,6 +441,16 @@
453
441
  ...extraFields
454
442
  };
455
443
  case "image":
444
+ if (field.list) {
445
+ return {
446
+ component: "list",
447
+ field: {
448
+ component: "image"
449
+ },
450
+ ...field,
451
+ ...extraFields
452
+ };
453
+ }
456
454
  return {
457
455
  component: "image",
458
456
  clearable: true,
@@ -613,9 +611,24 @@
613
611
  const name = z.z.string({
614
612
  required_error: "Name is required but not provided",
615
613
  invalid_type_error: "Name must be a string"
616
- }).refine((val) => val.match(/^[a-zA-Z0-9_]*$/) !== null, (val) => ({
617
- message: `name, "${val}" must be alphanumeric and can only contain underscores`
618
- }));
614
+ }).superRefine((val, ctx) => {
615
+ if (val.match(/^[a-zA-Z0-9_]*$/) === null) {
616
+ ctx.addIssue({
617
+ code: "custom",
618
+ message: `name, "${val}" must be alphanumeric and can only contain underscores. (No spaces, dashes, special characters, etc.)
619
+ If you only want to display this value in the CMS UI, you can use the label property to customize it.
620
+
621
+ If you need to use this value in your content you can use the \`nameOverride\` property to customize the value. For example:
622
+ \`\`\`
623
+ {
624
+ "name": ${val.replace(/[^a-zA-Z0-9]/g, "_")},
625
+ "nameOverride": ${val},
626
+ // ...
627
+ }
628
+ \`\`\``
629
+ });
630
+ }
631
+ });
619
632
  const TypeName = [
620
633
  "string",
621
634
  "boolean",
@@ -628,17 +641,6 @@
628
641
  ];
629
642
  const typeTypeError = `type must be one of ${TypeName.join(", ")}`;
630
643
  const typeRequiredError = `type is required and must be one of ${TypeName.join(", ")}`;
631
- const nameProp = z.z.string({
632
- required_error: "name must be provided",
633
- invalid_type_error: "name must be a sting"
634
- }).superRefine((val, ctx) => {
635
- if (val.includes(" "))
636
- ctx.addIssue({
637
- message: `name "${val}" cannot contain spaces`,
638
- code: z.z.ZodIssueCode.custom,
639
- fatal: true
640
- });
641
- });
642
644
  const Option = z.z.union([
643
645
  z.z.string(),
644
646
  z.z.object({ label: z.z.string(), value: z.z.string() }),
@@ -651,7 +653,7 @@
651
653
  }
652
654
  });
653
655
  const TinaField = z.z.object({
654
- name: nameProp,
656
+ name,
655
657
  label: z.z.string().or(z.z.boolean()).optional(),
656
658
  description: z.z.string().optional(),
657
659
  required: z.z.boolean().optional()
@@ -702,7 +704,7 @@
702
704
  const TinaFieldZod = z.z.lazy(() => {
703
705
  const TemplateTemp = z.z.object({
704
706
  label: z.z.string().optional(),
705
- name: nameProp,
707
+ name,
706
708
  fields: z.z.array(TinaFieldZod),
707
709
  match: z.z.object({
708
710
  start: z.z.string(),
@@ -863,7 +865,7 @@ ${JSON.stringify(val, null, 2)}
863
865
  });
864
866
  }
865
867
  });
866
- const TinaCloudCollectionBase = z.z.object({
868
+ const CollectionBaseSchema = z.z.object({
867
869
  label: z.z.string().optional(),
868
870
  name: name.superRefine((val, ctx) => {
869
871
  if (val === "relativePath") {
@@ -873,9 +875,10 @@ ${JSON.stringify(val, null, 2)}
873
875
  });
874
876
  }
875
877
  }),
878
+ path: z.z.string().transform((val) => val.replace(/^\/|\/$/g, "")),
876
879
  format: z.z.enum(FORMATS).optional()
877
880
  });
878
- const TinaCloudCollection = TinaCloudCollectionBase.extend({
881
+ const TinaCloudCollection = CollectionBaseSchema.extend({
879
882
  fields: z.z.array(TinaFieldZod).min(1).optional().superRefine((val, ctx) => {
880
883
  const dups = findDuplicates(val == null ? void 0 : val.map((x) => x.name));
881
884
  if (dups) {
@@ -937,9 +940,7 @@ ${JSON.stringify(val, null, 2)}
937
940
  this.name = "TinaSchemaValidationError";
938
941
  }
939
942
  }
940
- const validateSchema = ({
941
- schema
942
- }) => {
943
+ const validateSchema = ({ schema }) => {
943
944
  try {
944
945
  TinaCloudSchemaZod.parse(schema);
945
946
  } catch (e) {
@@ -1,4 +1,4 @@
1
- import { TinaCloudSchemaEnriched, TinaCloudSchemaBase, TinaCloudCollection, Templateable, Collectable, CollectionTemplateable } from '../types/index';
1
+ import { Schema, Collection, Template, Collectable, CollectionTemplateable } from '../types/index';
2
2
  declare type Version = {
3
3
  fullVersion: string;
4
4
  major: string;
@@ -17,39 +17,29 @@ export declare class TinaSchema {
17
17
  config: {
18
18
  version?: Version;
19
19
  meta?: Meta;
20
- } & TinaCloudSchemaBase;
21
- schema: TinaCloudSchemaEnriched;
20
+ } & Schema;
21
+ schema: Schema<true>;
22
22
  /**
23
- *
24
23
  * Create a schema class from a user defined schema object
25
- *
26
- * @param {{version?:Version;meta?:Meta}&TinaCloudSchemaBase} config
27
24
  */
28
25
  constructor(config: {
29
26
  version?: Version;
30
27
  meta?: Meta;
31
- } & TinaCloudSchemaBase);
28
+ } & Schema);
32
29
  getIsTitleFieldName: (collection: string) => string;
33
- getCollectionsByName: (collectionNames: string[]) => TinaCloudCollection<true>[];
30
+ getCollectionsByName: (collectionNames: string[]) => Collection<true>[];
34
31
  getAllCollectionPaths: () => string[];
35
- getCollection: (collectionName: string) => TinaCloudCollection<true>;
36
- getCollections: () => TinaCloudCollection<true>[];
37
- getGlobalTemplate: (templateName: string) => {
38
- label: string;
39
- name: string;
40
- ui?: import("../types/SchemaTypes").UICollection;
41
- fields: import("../types/SchemaTypes").TinaFieldInner<true>[];
42
- namespace: string[];
43
- };
44
- getCollectionByFullPath: (filepath: string) => TinaCloudCollection<true>;
32
+ getCollection: (collectionName: string) => Collection<true>;
33
+ getCollections: () => Collection<true>[];
34
+ getCollectionByFullPath: (filepath: string) => Collection<true>;
45
35
  getCollectionAndTemplateByFullPath: (filepath: string, templateName?: string) => {
46
- collection: TinaCloudCollection<true>;
47
- template: Templateable;
36
+ collection: Collection<true>;
37
+ template: Template<true>;
48
38
  };
49
39
  getTemplateForData: ({ data, collection, }: {
50
40
  data?: unknown;
51
41
  collection: Collectable;
52
- }) => Templateable;
42
+ }) => Template<true>;
53
43
  transformPayload: (collectionName: string, payload: object) => {
54
44
  [x: string]: {
55
45
  [x: string]: {};
@@ -1,20 +1,14 @@
1
1
  /**
2
2
 
3
3
  */
4
- import { TinaFieldEnriched } from '../types/index';
4
+ import { TinaField } from '../types/index';
5
5
  import { TinaSchema } from './TinaSchema';
6
6
  /**
7
- *
8
7
  * Turns a field the schema (schema.{js,ts} file) into a valid front end FieldConfig
9
- *
10
- *
11
- * @param {TinaFieldEnriched} field. The field that will be transformed
12
- * @param {TinaSchema} schema the entireT Tina Schema
13
- * @returns unknown
14
8
  */
15
- export declare const resolveField: (field: TinaFieldEnriched, schema: TinaSchema) => {
9
+ export declare const resolveField: (field: TinaField<true>, schema: TinaSchema) => {
16
10
  [key: string]: unknown;
17
11
  name: string;
18
- component: string;
12
+ component: TinaField<true>['ui']['component'];
19
13
  type: string;
20
14
  };
@@ -1,7 +1,8 @@
1
1
  /**
2
2
 
3
3
  */
4
- import type { ResolveFormArgs } from '../types/index';
4
+ import type { Template, Collection } from '../types/index';
5
+ import type { TinaSchema } from './TinaSchema';
5
6
  /**
6
7
  * Given a collection, basename, template and schema. This will transform the given information into a valid frontend form config
7
8
  */
@@ -12,7 +13,156 @@ export declare const resolveForm: ({ collection, basename, template, schema, }:
12
13
  fields: {
13
14
  [key: string]: unknown;
14
15
  name: string;
15
- component: string;
16
+ component: string | ((props: {
17
+ field: import("../types/index").TinaField<false> & {
18
+ namespace: string[];
19
+ };
20
+ input: {
21
+ name: string;
22
+ onBlur: (event?: any) => void;
23
+ onChange: (event: any) => void;
24
+ onFocus: (event?: any) => void;
25
+ type?: string;
26
+ value: string[];
27
+ };
28
+ meta: {
29
+ active?: boolean;
30
+ dirty?: boolean;
31
+ error?: any;
32
+ };
33
+ }) => any) | ((props: {
34
+ field: import("../types/index").TinaField<false> & {
35
+ namespace: string[];
36
+ };
37
+ input: {
38
+ name: string;
39
+ onBlur: (event?: any) => void;
40
+ onChange: (event: any) => void;
41
+ onFocus: (event?: any) => void;
42
+ type?: string;
43
+ value: number[];
44
+ };
45
+ meta: {
46
+ active?: boolean;
47
+ dirty?: boolean;
48
+ error?: any;
49
+ };
50
+ }) => any) | ((props: {
51
+ field: import("../types/index").TinaField<false> & {
52
+ namespace: string[];
53
+ };
54
+ input: {
55
+ name: string;
56
+ onBlur: (event?: any) => void;
57
+ onChange: (event: any) => void;
58
+ onFocus: (event?: any) => void;
59
+ type?: string;
60
+ value: boolean[];
61
+ };
62
+ meta: {
63
+ active?: boolean;
64
+ dirty?: boolean;
65
+ error?: any;
66
+ };
67
+ }) => any) | ((props: {
68
+ field: import("../types/index").TinaField<false> & {
69
+ namespace: string[];
70
+ };
71
+ input: {
72
+ name: string;
73
+ onBlur: (event?: any) => void;
74
+ onChange: (event: any) => void;
75
+ onFocus: (event?: any) => void;
76
+ type?: string;
77
+ value: {
78
+ type: "root";
79
+ children: Record<string, unknown>[];
80
+ }[];
81
+ };
82
+ meta: {
83
+ active?: boolean;
84
+ dirty?: boolean;
85
+ error?: any;
86
+ };
87
+ }) => any) | ((props: {
88
+ field: import("../types/index").TinaField<false> & {
89
+ namespace: string[];
90
+ };
91
+ input: {
92
+ name: string;
93
+ onBlur: (event?: any) => void;
94
+ onChange: (event: any) => void;
95
+ onFocus: (event?: any) => void;
96
+ type?: string;
97
+ value: string;
98
+ };
99
+ meta: {
100
+ active?: boolean;
101
+ dirty?: boolean;
102
+ error?: any;
103
+ };
104
+ }) => any) | ((props: {
105
+ field: import("../types/index").TinaField<false> & {
106
+ namespace: string[];
107
+ };
108
+ input: {
109
+ name: string;
110
+ onBlur: (event?: any) => void;
111
+ onChange: (event: any) => void;
112
+ onFocus: (event?: any) => void;
113
+ type?: string;
114
+ value: number;
115
+ };
116
+ meta: {
117
+ active?: boolean;
118
+ dirty?: boolean;
119
+ error?: any;
120
+ };
121
+ }) => any) | ((props: {
122
+ field: import("../types/index").TinaField<false> & {
123
+ namespace: string[];
124
+ };
125
+ input: {
126
+ name: string;
127
+ onBlur: (event?: any) => void;
128
+ onChange: (event: any) => void;
129
+ onFocus: (event?: any) => void;
130
+ type?: string;
131
+ value: boolean;
132
+ };
133
+ meta: {
134
+ active?: boolean;
135
+ dirty?: boolean;
136
+ error?: any;
137
+ };
138
+ }) => any) | ((props: {
139
+ field: import("../types/index").TinaField<false> & {
140
+ namespace: string[];
141
+ };
142
+ input: {
143
+ name: string;
144
+ onBlur: (event?: any) => void;
145
+ onChange: (event: any) => void;
146
+ onFocus: (event?: any) => void;
147
+ type?: string;
148
+ value: {
149
+ type: "root";
150
+ children: Record<string, unknown>[];
151
+ };
152
+ };
153
+ meta: {
154
+ active?: boolean;
155
+ dirty?: boolean;
156
+ error?: any;
157
+ };
158
+ }) => any);
16
159
  type: string;
17
160
  }[];
18
161
  };
162
+ declare type ResolveFormArgs = {
163
+ collection: Collection<true>;
164
+ basename: string;
165
+ template: Template<true>;
166
+ schema: TinaSchema;
167
+ };
168
+ export {};