prismic-ts-codegen 0.0.7 → 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.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Project, ModuleDeclarationKind } from 'ts-morph';
2
2
  import { stripIndent } from 'common-tags';
3
- import { CustomTypeModelFieldType, CustomTypeModelLinkSelectType, CustomTypeModelSliceType } from '@prismicio/types';
3
+ import { CustomTypeModelSliceType, CustomTypeModelFieldType, CustomTypeModelLinkSelectType } from '@prismicio/types';
4
4
  import { pascalCase as pascalCase$1, pascalCaseTransformMerge } from 'pascal-case';
5
5
 
6
6
  const BLANK_LINE_IDENTIFIER = "// ___BLANK_LINE_TO_BE_REPLACED___";
@@ -26,19 +26,24 @@ const FIELD_DOCUMENTATION_URLS = {
26
26
  GeoPoint: "https://prismic.io/docs/core-concepts/geopoint",
27
27
  Group: "https://prismic.io/docs/core-concepts/group",
28
28
  IntegrationFields: "https://prismic.io/docs/core-concepts/integration-fields",
29
- Slices: "https://prismic.io/docs/core-concepts/slices"
29
+ Slices: "https://prismic.io/docs/core-concepts/slices",
30
+ LegacySlices: "https://prismic.io/docs/core-concepts/slices"
30
31
  };
31
32
 
32
33
  const isCustomTypeModelField = (model) => {
33
- return typeof model === "object" && model !== null && "type" in model && "config" in model;
34
+ return typeof model === "object" && model !== null && "type" in model;
35
+ };
36
+
37
+ const hasOwnProperty = (obj, prop) => {
38
+ return obj.hasOwnProperty(prop);
34
39
  };
35
40
 
36
41
  const isCustomTypeModelSlice = (model) => {
37
- return typeof model === "object" && model !== null && "non-repeat" in model && "repeat" in model;
42
+ return typeof model === "object" && model !== null && hasOwnProperty(model, "type") && model.type === CustomTypeModelSliceType.Slice;
38
43
  };
39
44
 
40
45
  const isSharedSliceModel = (model) => {
41
- return typeof model === "object" && model !== null && "variations" in model;
46
+ return typeof model === "object" && model !== null && hasOwnProperty(model, "type") && model.type === CustomTypeModelSliceType.SharedSlice;
42
47
  };
43
48
 
44
49
  const getAPIIDPath = (config) => {
@@ -67,16 +72,19 @@ const isCustomTypeModel = (model) => {
67
72
 
68
73
  const getHumanReadableModelName = (config) => {
69
74
  if (isCustomTypeModel(config.model)) {
70
- return config.model.label;
75
+ return config.model.label || config.model.id;
71
76
  } else if (isSharedSliceModel(config.model)) {
72
77
  return config.model.name;
73
- } else if (isCustomTypeModelField(config.model) && "label" in config.model.config) {
74
- return config.model.config.label;
78
+ } else if (isCustomTypeModelField(config.model)) {
79
+ if (config.model.config && "label" in config.model.config) {
80
+ return config.model.config.label || config.id;
81
+ } else if (config.model.config && "fieldset" in config.model) {
82
+ return config.model.fieldset || config.id;
83
+ }
75
84
  } else if (isCustomTypeModelSlice(config.model)) {
76
- return config.model.fieldset;
77
- } else {
78
- return `Slice Zone (\`${config.id}\`)`;
85
+ return config.model.fieldset || config.id;
79
86
  }
87
+ return `\`${config.id}\``;
80
88
  };
81
89
 
82
90
  const getHumanReadableFieldPath = (config) => {
@@ -97,14 +105,15 @@ const getHumanReadableFieldPath = (config) => {
97
105
  const getHumanReadableFieldType = (config) => {
98
106
  switch (config.model.type) {
99
107
  case "StructuredText": {
100
- const isTitleField = "single" in config.model.config && config.model.config.single.split(",").every((blockType) => /heading/.test(blockType));
108
+ const isTitleField = config.model.config && "single" in config.model.config && config.model.config.single && config.model.config.single.split(",").every((blockType) => /heading/.test(blockType));
101
109
  return isTitleField ? "Title" : "Rich Text";
102
110
  }
103
111
  case "IntegrationFields": {
104
- return `Integration Fields (Catalog: \`${config.model.config.catalog}\`)`;
112
+ const catalog = config.model.config?.catalog;
113
+ return `Integration Fields (Catalog: ${catalog ? `\`${catalog}\`` : "*unknown*"})`;
105
114
  }
106
115
  case "Link": {
107
- switch (config.model.config.select) {
116
+ switch (config.model.config?.select) {
108
117
  case CustomTypeModelLinkSelectType.Document: {
109
118
  return "Content Relationship";
110
119
  }
@@ -165,8 +174,8 @@ const buildFieldDocs = (config) => {
165
174
  const fieldType = getHumanReadableFieldType({
166
175
  model: config.model
167
176
  });
168
- const placeholder = "placeholder" in config.model.config && config.model.config.placeholder ? config.model.config.placeholder : `*None*`;
169
- const defaultValue = "default_value" in config.model.config ? config.model.config.default_value : void 0;
177
+ const placeholder = config.model.config && "placeholder" in config.model.config && config.model.config.placeholder ? config.model.config.placeholder : `*None*`;
178
+ const defaultValue = config.model.config && "default_value" in config.model.config ? config.model.config.default_value : void 0;
170
179
  const apiIDPath = getAPIIDPath({
171
180
  path: [...config.path, { id: config.id, model: config.model }]
172
181
  });
@@ -271,7 +280,7 @@ const addInterfacePropertyForField = (config) => {
271
280
  break;
272
281
  }
273
282
  case "Image": {
274
- if (config.model.config.thumbnails.length > 0) {
283
+ if (config.model.config?.thumbnails && config.model.config.thumbnails.length > 0) {
275
284
  const thumbnailNames = config.model.config.thumbnails.map((thumbnail) => `"${thumbnail.name}"`).join(" | ");
276
285
  config.interface.addProperty({
277
286
  name: config.id,
@@ -286,7 +295,7 @@ const addInterfacePropertyForField = (config) => {
286
295
  } else {
287
296
  config.interface.addProperty({
288
297
  name: config.id,
289
- type: "prismicT.ImageField<null>",
298
+ type: "prismicT.ImageField<never>",
290
299
  docs: buildFieldDocs({
291
300
  id: config.id,
292
301
  model: config.model,
@@ -298,7 +307,7 @@ const addInterfacePropertyForField = (config) => {
298
307
  break;
299
308
  }
300
309
  case "IntegrationFields": {
301
- const catalogType = config.fieldConfigs.integrationFields?.catalogTypes?.[config.model.config.catalog];
310
+ const catalogType = config.model.config?.catalog ? config.fieldConfigs.integrationFields?.catalogTypes?.[config.model.config.catalog] : void 0;
302
311
  config.interface.addProperty({
303
312
  name: config.id,
304
313
  type: catalogType ? `prismicT.IntegrationFields<${catalogType}>` : "prismicT.IntegrationFields",
@@ -312,11 +321,12 @@ const addInterfacePropertyForField = (config) => {
312
321
  break;
313
322
  }
314
323
  case "Link": {
315
- switch (config.model.config.select) {
324
+ switch (config.model.config?.select) {
316
325
  case CustomTypeModelLinkSelectType.Document: {
326
+ config.model.config;
317
327
  config.interface.addProperty({
318
328
  name: config.id,
319
- type: config.model.config.customtypes && config.model.config.customtypes.length > 0 ? `prismicT.RelationField<${config.model.config.customtypes.map((type) => `"${type}"`).join(" | ")}>` : "prismicT.RelationField",
329
+ type: "customtypes" in config.model.config && config.model.config.customtypes && config.model.config.customtypes.length > 0 ? `prismicT.RelationField<${config.model.config.customtypes.map((type) => `"${type}"`).join(" | ")}>` : "prismicT.RelationField",
320
330
  docs: buildFieldDocs({
321
331
  id: config.id,
322
332
  model: config.model,
@@ -368,7 +378,7 @@ const addInterfacePropertyForField = (config) => {
368
378
  break;
369
379
  }
370
380
  case "StructuredText": {
371
- const isTitleField = "single" in config.model.config && config.model.config.single.split(",").every((blockType) => /heading/.test(blockType));
381
+ const isTitleField = config.model.config && "single" in config.model.config && config.model.config.single && config.model.config.single.split(",").every((blockType) => /heading/.test(blockType));
372
382
  if (isTitleField) {
373
383
  config.interface.addProperty({
374
384
  name: config.id,
@@ -395,12 +405,12 @@ const addInterfacePropertyForField = (config) => {
395
405
  break;
396
406
  }
397
407
  case "Select": {
398
- const options = config.model.config.options.map((option) => `"${option}"`).join(" | ");
399
- const hasDefault = Boolean(config.model.config.default_value);
408
+ const options = config.model.config?.options?.map((option) => `"${option}"`).join(" | ");
409
+ const hasDefault = Boolean(config.model.config?.default_value);
400
410
  if (hasDefault) {
401
411
  config.interface.addProperty({
402
412
  name: config.id,
403
- type: `prismicT.SelectField<${options}, "filled">`,
413
+ type: `prismicT.SelectField<${options || "string"}, "filled">`,
404
414
  docs: buildFieldDocs({
405
415
  id: config.id,
406
416
  model: config.model,
@@ -469,19 +479,21 @@ const addInterfacePropertyForField = (config) => {
469
479
  ],
470
480
  isExported: true
471
481
  });
472
- addInterfacePropertiesForFields({
473
- interface: itemInterface,
474
- sourceFile: config.sourceFile,
475
- fields: config.model.config.fields,
476
- path: [
477
- ...config.path,
478
- {
479
- id: config.id,
480
- model: config.model
481
- }
482
- ],
483
- fieldConfigs: config.fieldConfigs
484
- });
482
+ if (config.model.config?.fields) {
483
+ addInterfacePropertiesForFields({
484
+ interface: itemInterface,
485
+ sourceFile: config.sourceFile,
486
+ fields: config.model.config.fields,
487
+ path: [
488
+ ...config.path,
489
+ {
490
+ id: config.id,
491
+ model: config.model
492
+ }
493
+ ],
494
+ fieldConfigs: config.fieldConfigs
495
+ });
496
+ }
485
497
  config.interface.addProperty({
486
498
  name: config.id,
487
499
  type: `prismicT.GroupField<Simplify<${itemInterface.getName()}>>`,
@@ -496,120 +508,122 @@ const addInterfacePropertyForField = (config) => {
496
508
  }
497
509
  case "Slices": {
498
510
  const choiceInterfaceNames = [];
499
- for (const choiceId in config.model.config.choices) {
500
- const choice = config.model.config.choices[choiceId];
501
- if (choice.type === CustomTypeModelSliceType.SharedSlice) {
502
- choiceInterfaceNames.push(buildSharedSliceInterfaceName({ id: choiceId }));
503
- } else if (choice.type === CustomTypeModelSliceType.Slice) {
504
- let primaryInterface;
505
- if (Object.keys(choice["non-repeat"]).length > 0) {
506
- primaryInterface = config.sourceFile.addInterface({
507
- name: pascalCase(`${config.path[0].id} Document Data ${config.id} ${choiceId} Slice Primary`),
508
- docs: [
509
- {
510
- description: (writer) => {
511
- const humanReadablePath = getHumanReadableFieldPath({
512
- path: [
513
- ...config.path,
514
- {
515
- id: config.id,
516
- model: config.model
517
- },
518
- {
519
- id: choiceId,
520
- model: choice
521
- },
522
- {
523
- id: "primary",
524
- label: "Primary"
525
- }
526
- ]
527
- });
528
- writer.writeLine(`Primary content in ${humanReadablePath}`);
511
+ if (config.model.config?.choices) {
512
+ for (const choiceId in config.model.config.choices) {
513
+ const choice = config.model.config.choices[choiceId];
514
+ if (choice.type === CustomTypeModelSliceType.SharedSlice) {
515
+ choiceInterfaceNames.push(buildSharedSliceInterfaceName({ id: choiceId }));
516
+ } else if (choice.type === CustomTypeModelSliceType.Slice) {
517
+ let primaryInterface;
518
+ if (choice["non-repeat"] && Object.keys(choice["non-repeat"]).length > 0) {
519
+ primaryInterface = config.sourceFile.addInterface({
520
+ name: pascalCase(`${config.path[0].id} Document Data ${config.id} ${choiceId} Slice Primary`),
521
+ docs: [
522
+ {
523
+ description: (writer) => {
524
+ const humanReadablePath = getHumanReadableFieldPath({
525
+ path: [
526
+ ...config.path,
527
+ {
528
+ id: config.id,
529
+ model: config.model
530
+ },
531
+ {
532
+ id: choiceId,
533
+ model: choice
534
+ },
535
+ {
536
+ id: "primary",
537
+ label: "Primary"
538
+ }
539
+ ]
540
+ });
541
+ writer.writeLine(`Primary content in ${humanReadablePath}`);
542
+ }
529
543
  }
530
- }
531
- ]
532
- });
533
- addInterfacePropertiesForFields({
534
- interface: primaryInterface,
535
- sourceFile: config.sourceFile,
536
- fields: choice["non-repeat"],
537
- path: [
538
- ...config.path,
539
- {
540
- id: config.id,
541
- model: config.model
542
- },
543
- {
544
- id: choiceId,
545
- model: choice
546
- },
547
- {
548
- id: "primary",
549
- label: "Primary"
550
- }
551
- ],
552
- fieldConfigs: config.fieldConfigs
553
- });
554
- }
555
- let itemInterface;
556
- if (Object.keys(choice.repeat).length > 0) {
557
- itemInterface = config.sourceFile.addInterface({
558
- name: pascalCase(`${config.path[0].id} Document Data ${config.id} ${choiceId} Slice Item`),
559
- docs: [
560
- {
561
- description: (writer) => {
562
- const humanReadablePath = getHumanReadableFieldPath({
563
- path: [
564
- ...config.path,
565
- {
566
- id: config.id,
567
- model: config.model
568
- },
569
- {
570
- id: choiceId,
571
- model: choice
572
- },
573
- {
574
- id: "items",
575
- label: "Items"
576
- }
577
- ]
578
- });
579
- writer.writeLine(`Item in ${humanReadablePath}`);
544
+ ]
545
+ });
546
+ addInterfacePropertiesForFields({
547
+ interface: primaryInterface,
548
+ sourceFile: config.sourceFile,
549
+ fields: choice["non-repeat"],
550
+ path: [
551
+ ...config.path,
552
+ {
553
+ id: config.id,
554
+ model: config.model
555
+ },
556
+ {
557
+ id: choiceId,
558
+ model: choice
559
+ },
560
+ {
561
+ id: "primary",
562
+ label: "Primary"
580
563
  }
581
- }
582
- ],
564
+ ],
565
+ fieldConfigs: config.fieldConfigs
566
+ });
567
+ }
568
+ let itemInterface;
569
+ if (choice.repeat && Object.keys(choice.repeat).length > 0) {
570
+ itemInterface = config.sourceFile.addInterface({
571
+ name: pascalCase(`${config.path[0].id} Document Data ${config.id} ${choiceId} Slice Item`),
572
+ docs: [
573
+ {
574
+ description: (writer) => {
575
+ const humanReadablePath = getHumanReadableFieldPath({
576
+ path: [
577
+ ...config.path,
578
+ {
579
+ id: config.id,
580
+ model: config.model
581
+ },
582
+ {
583
+ id: choiceId,
584
+ model: choice
585
+ },
586
+ {
587
+ id: "items",
588
+ label: "Items"
589
+ }
590
+ ]
591
+ });
592
+ writer.writeLine(`Item in ${humanReadablePath}`);
593
+ }
594
+ }
595
+ ],
596
+ isExported: true
597
+ });
598
+ addInterfacePropertiesForFields({
599
+ interface: itemInterface,
600
+ sourceFile: config.sourceFile,
601
+ fields: choice.repeat,
602
+ path: [
603
+ ...config.path,
604
+ {
605
+ id: config.id,
606
+ model: config.model
607
+ },
608
+ {
609
+ id: choiceId,
610
+ model: choice
611
+ },
612
+ {
613
+ id: "items",
614
+ label: "Items"
615
+ }
616
+ ],
617
+ fieldConfigs: config.fieldConfigs
618
+ });
619
+ }
620
+ const sliceType = config.sourceFile.addTypeAlias({
621
+ name: pascalCase(`${config.path[0].id} Document Data ${config.id} ${choiceId} Slice`),
622
+ type: `prismicT.Slice<"${choiceId}", ${primaryInterface ? `Simplify<${primaryInterface.getName()}>` : "Record<string, never>"}, ${itemInterface ? `Simplify<${itemInterface.getName()}>` : "never"}>`,
583
623
  isExported: true
584
624
  });
585
- addInterfacePropertiesForFields({
586
- interface: itemInterface,
587
- sourceFile: config.sourceFile,
588
- fields: choice.repeat,
589
- path: [
590
- ...config.path,
591
- {
592
- id: config.id,
593
- model: config.model
594
- },
595
- {
596
- id: choiceId,
597
- model: choice
598
- },
599
- {
600
- id: "items",
601
- label: "Items"
602
- }
603
- ],
604
- fieldConfigs: config.fieldConfigs
605
- });
625
+ choiceInterfaceNames.push(sliceType.getName());
606
626
  }
607
- const sliceType = config.sourceFile.addTypeAlias({
608
- name: pascalCase(`${config.path[0].id} Document Data ${config.id} ${choiceId} Slice`),
609
- type: `prismicT.Slice<"${choiceId}", ${primaryInterface ? `Simplify<${primaryInterface.getName()}>` : "Record<string, never>"}, ${itemInterface ? `Simplify<${itemInterface.getName()}>` : "never"}>`,
610
- isExported: true
611
- });
612
- choiceInterfaceNames.push(sliceType.getName());
613
627
  }
614
628
  }
615
629
  const slicesType = config.sourceFile.addTypeAlias({
@@ -662,7 +676,7 @@ const addInterfacePropertiesForFields = (config) => {
662
676
  for (const name in config.fields) {
663
677
  addInterfacePropertyForField({
664
678
  ...config,
665
- id: name.includes("-") ? `"${name}"` : name,
679
+ id: name.includes("-") || /^[0-9]/.test(name) ? `"${name}"` : name,
666
680
  model: config.fields[name],
667
681
  tabName: config.tabName
668
682
  });
@@ -753,7 +767,7 @@ const addTypeAliasForSharedSlice = (config) => {
753
767
  const variationTypeNames = [];
754
768
  for (const variation of config.model.variations) {
755
769
  let primaryInterface;
756
- if (Object.keys(variation.primary).length > 0) {
770
+ if (variation.primary && Object.keys(variation.primary).length > 0) {
757
771
  primaryInterface = config.sourceFile.addInterface({
758
772
  name: pascalCase(`${buildSharedSliceInterfaceName({ id: config.model.id })} ${variation.id} Primary`),
759
773
  docs: [
@@ -794,7 +808,7 @@ const addTypeAliasForSharedSlice = (config) => {
794
808
  });
795
809
  }
796
810
  let itemInterface;
797
- if (Object.keys(variation.items).length > 0) {
811
+ if (variation.items && Object.keys(variation.items).length > 0) {
798
812
  itemInterface = config.sourceFile.addInterface({
799
813
  name: pascalCase(`${buildSharedSliceInterfaceName({ id: config.model.id })} ${variation.id} Item`),
800
814
  docs: [