@angeloashmore/prismic-cli-poc 0.0.0-pr.6.9baab87 → 0.0.0-pr.8.b80fefa

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.
Files changed (63) hide show
  1. package/dist/index.mjs +277 -432
  2. package/package.json +1 -1
  3. package/src/custom-type-add-field-boolean.ts +5 -12
  4. package/src/custom-type-add-field-color.ts +6 -12
  5. package/src/custom-type-add-field-date.ts +6 -12
  6. package/src/custom-type-add-field-embed.ts +6 -12
  7. package/src/custom-type-add-field-geo-point.ts +6 -12
  8. package/src/custom-type-add-field-image.ts +6 -12
  9. package/src/custom-type-add-field-key-text.ts +6 -12
  10. package/src/custom-type-add-field-link.ts +5 -12
  11. package/src/custom-type-add-field-number.ts +6 -12
  12. package/src/custom-type-add-field-rich-text.ts +5 -12
  13. package/src/custom-type-add-field-select.ts +5 -12
  14. package/src/custom-type-add-field-timestamp.ts +6 -12
  15. package/src/custom-type-add-field-uid.ts +6 -12
  16. package/src/custom-type-connect-slice.ts +6 -12
  17. package/src/custom-type-create.ts +6 -12
  18. package/src/custom-type-disconnect-slice.ts +6 -12
  19. package/src/custom-type-remove-field.ts +6 -12
  20. package/src/custom-type-remove.ts +6 -12
  21. package/src/custom-type-set-name.ts +6 -12
  22. package/src/docs.ts +149 -0
  23. package/src/index.ts +5 -0
  24. package/src/page-type-add-field-boolean.ts +5 -12
  25. package/src/page-type-add-field-color.ts +6 -12
  26. package/src/page-type-add-field-date.ts +6 -12
  27. package/src/page-type-add-field-embed.ts +6 -12
  28. package/src/page-type-add-field-geo-point.ts +6 -12
  29. package/src/page-type-add-field-image.ts +6 -12
  30. package/src/page-type-add-field-key-text.ts +6 -12
  31. package/src/page-type-add-field-link.ts +5 -12
  32. package/src/page-type-add-field-number.ts +6 -12
  33. package/src/page-type-add-field-rich-text.ts +5 -12
  34. package/src/page-type-add-field-select.ts +5 -12
  35. package/src/page-type-add-field-timestamp.ts +6 -12
  36. package/src/page-type-add-field-uid.ts +6 -12
  37. package/src/page-type-connect-slice.ts +6 -12
  38. package/src/page-type-create.ts +6 -12
  39. package/src/page-type-disconnect-slice.ts +6 -12
  40. package/src/page-type-remove-field.ts +6 -12
  41. package/src/page-type-remove.ts +6 -12
  42. package/src/page-type-set-name.ts +6 -12
  43. package/src/page-type-set-repeatable.ts +6 -12
  44. package/src/pull.ts +1 -6
  45. package/src/slice-add-field-boolean.ts +5 -12
  46. package/src/slice-add-field-color.ts +6 -12
  47. package/src/slice-add-field-date.ts +6 -12
  48. package/src/slice-add-field-embed.ts +6 -12
  49. package/src/slice-add-field-geo-point.ts +6 -12
  50. package/src/slice-add-field-image.ts +6 -12
  51. package/src/slice-add-field-key-text.ts +6 -12
  52. package/src/slice-add-field-link.ts +5 -12
  53. package/src/slice-add-field-number.ts +6 -12
  54. package/src/slice-add-field-rich-text.ts +5 -12
  55. package/src/slice-add-field-select.ts +5 -12
  56. package/src/slice-add-field-timestamp.ts +6 -12
  57. package/src/slice-add-variation.ts +6 -12
  58. package/src/slice-create.ts +6 -12
  59. package/src/slice-remove-field.ts +6 -12
  60. package/src/slice-remove-variation.ts +6 -12
  61. package/src/slice-remove.ts +6 -12
  62. package/src/slice-rename.ts +6 -12
  63. package/src/status.ts +113 -13
package/src/status.ts CHANGED
@@ -66,16 +66,53 @@ type NextStep = {
66
66
  message: string;
67
67
  };
68
68
 
69
- function getDocsUrl(framework: Framework | undefined): string {
69
+ function getDocsPath(framework: Framework | undefined): string {
70
70
  switch (framework) {
71
71
  case "next":
72
- return "https://prismic.io/docs/nextjs/with-cli";
72
+ return "nextjs/with-cli";
73
73
  case "nuxt":
74
- return "https://prismic.io/docs/nuxt/with-cli";
74
+ return "nuxt/with-cli";
75
75
  case "sveltekit":
76
- return "https://prismic.io/docs/sveltekit/with-cli";
76
+ return "sveltekit/with-cli";
77
77
  default:
78
- return "https://prismic.io/docs";
78
+ return "";
79
+ }
80
+ }
81
+
82
+ function getDocsRef(docsPath: string, anchor?: string): string {
83
+ if (!docsPath) return "";
84
+ const fullPath = anchor ? `${docsPath}${anchor}` : docsPath;
85
+ return ` (run \`prismic docs ${fullPath}\`)`;
86
+ }
87
+
88
+ function getClientSetupAnchor(framework: Framework | undefined): string {
89
+ switch (framework) {
90
+ case "nuxt":
91
+ return "#configure-the-modules-prismic-client";
92
+ default:
93
+ return "#set-up-a-prismic-client";
94
+ }
95
+ }
96
+
97
+ function getPreviewSetupAnchor(framework: Framework | undefined): string {
98
+ switch (framework) {
99
+ case "next":
100
+ return "#set-up-previews-in-next-js";
101
+ case "sveltekit":
102
+ return "#set-up-previews-in-sveltekit";
103
+ default:
104
+ return "";
105
+ }
106
+ }
107
+
108
+ function getWriteComponentsAnchor(framework: Framework | undefined): string {
109
+ switch (framework) {
110
+ case "nuxt":
111
+ return "#write-vue-components";
112
+ case "sveltekit":
113
+ return "#write-svelte-components";
114
+ default:
115
+ return "#write-react-components";
79
116
  }
80
117
  }
81
118
 
@@ -85,8 +122,9 @@ function computeNextStep(
85
122
  typeStatuses: TypeWithStatus[],
86
123
  sliceStatuses: TypeWithStatus[],
87
124
  slicesWithMissingComponents: string[],
125
+ slicesReadyToConnect: string[],
88
126
  ): NextStep | undefined {
89
- const docsUrl = getDocsUrl(frameworkInfo.framework);
127
+ const docsPath = getDocsPath(frameworkInfo.framework);
90
128
 
91
129
  // 1. Setup - missing dependencies
92
130
  const setupSection = sections.find((s) => s.title === "Setup");
@@ -99,7 +137,7 @@ function computeNextStep(
99
137
  // 2. Setup - missing client file
100
138
  const missingClientFile = setupSection?.items.find((i) => !i.done && i.hint?.includes("client"));
101
139
  if (missingClientFile) {
102
- return { message: `Create a ${missingClientFile.label} file (see ${docsUrl})` };
140
+ return { message: `Create a ${missingClientFile.label} file${getDocsRef(docsPath, getClientSetupAnchor(frameworkInfo.framework))}` };
103
141
  }
104
142
 
105
143
  // 3-7. Preview section (in order: local files, then remote config)
@@ -110,21 +148,21 @@ function computeNextStep(
110
148
  (i) => i.label === "/slice-simulator route" && !i.done,
111
149
  );
112
150
  if (sliceSimRoute) {
113
- return { message: `Create the /slice-simulator route (see ${docsUrl})` };
151
+ return { message: `Create the /slice-simulator route${getDocsRef(docsPath, "#set-up-live-previewing")}` };
114
152
  }
115
153
 
116
154
  const apiPreview = previewSection.items.find(
117
155
  (i) => i.label === "/api/preview endpoint" && !i.done,
118
156
  );
119
157
  if (apiPreview) {
120
- return { message: `Create the /api/preview route (see ${docsUrl})` };
158
+ return { message: `Create the /api/preview route${getDocsRef(docsPath, getPreviewSetupAnchor(frameworkInfo.framework))}` };
121
159
  }
122
160
 
123
161
  const exitPreview = previewSection.items.find(
124
162
  (i) => i.label === "/api/exit-preview endpoint" && !i.done,
125
163
  );
126
164
  if (exitPreview) {
127
- return { message: `Create the /api/exit-preview route (see ${docsUrl})` };
165
+ return { message: `Create the /api/exit-preview route${getDocsRef(docsPath, getPreviewSetupAnchor(frameworkInfo.framework))}` };
128
166
  }
129
167
 
130
168
  // Remote config
@@ -151,6 +189,15 @@ function computeNextStep(
151
189
  return { message: `Pull remote models with 'prismic pull'` };
152
190
  }
153
191
 
192
+ // 8.5 Slices ready to connect to a page type (before pushing)
193
+ if (slicesReadyToConnect.length > 0) {
194
+ const sorted = [...slicesReadyToConnect].sort();
195
+ const sliceName = sorted[0];
196
+ return {
197
+ message: `Connect ${sliceName} to a page type with 'prismic page-type connect-slice <type-id> ${sliceName}'`,
198
+ };
199
+ }
200
+
154
201
  // 9. Models to push
155
202
  const hasToPush =
156
203
  typeStatuses.some((t) => t.status === "to_push") ||
@@ -166,7 +213,7 @@ function computeNextStep(
166
213
  const slicesDir = getSlicesDirectory(frameworkInfo);
167
214
  const ext = getSliceComponentExtensions(frameworkInfo.framework)[0];
168
215
  const path = `${slicesDir}${sliceName}/index${ext}`;
169
- return { message: `Implement the ${sliceName} slice component at ${path} (see ${docsUrl})` };
216
+ return { message: `Implement the ${sliceName} slice component at ${path}${getDocsRef(docsPath, getWriteComponentsAnchor(frameworkInfo.framework))}` };
170
217
  }
171
218
 
172
219
  // 11-12. Deployment (Next.js only)
@@ -176,7 +223,7 @@ function computeNextStep(
176
223
  (i) => i.label === "/api/revalidate endpoint" && !i.done,
177
224
  );
178
225
  if (revalidateEndpoint) {
179
- return { message: `Create the /api/revalidate route for ISR (see ${docsUrl})` };
226
+ return { message: `Create the /api/revalidate route for ISR${getDocsRef(docsPath, "#handle-content-changes")}` };
180
227
  }
181
228
 
182
229
  const webhook = deploymentSection.items.find(
@@ -261,6 +308,7 @@ export async function status(): Promise<void> {
261
308
  let typeStatuses: TypeWithStatus[] = [];
262
309
  let sliceStatuses: TypeWithStatus[] = [];
263
310
  let slicesWithMissingComponents: string[] = [];
311
+ let slicesReadyToConnect: string[] = [];
264
312
 
265
313
  // Setup section
266
314
  const setupSection = await buildSetupSection(frameworkInfo, installedDeps);
@@ -283,10 +331,17 @@ export async function status(): Promise<void> {
283
331
  section: slicesSection,
284
332
  statuses,
285
333
  missingComponents,
286
- } = await buildSlicesSection(localSlicesResult.value, remoteSlicesResult.value, frameworkInfo);
334
+ slicesReadyToConnect: readyToConnect,
335
+ } = await buildSlicesSection(
336
+ localSlicesResult.value,
337
+ remoteSlicesResult.value,
338
+ frameworkInfo,
339
+ localTypesResult.ok ? localTypesResult.value : [],
340
+ );
287
341
  sections.push(slicesSection);
288
342
  sliceStatuses = statuses;
289
343
  slicesWithMissingComponents = missingComponents;
344
+ slicesReadyToConnect = readyToConnect;
290
345
  }
291
346
 
292
347
  // Preview section
@@ -318,6 +373,7 @@ export async function status(): Promise<void> {
318
373
  typeStatuses,
319
374
  sliceStatuses,
320
375
  slicesWithMissingComponents,
376
+ slicesReadyToConnect,
321
377
  );
322
378
  if (nextStep) {
323
379
  console.info(`Next: ${nextStep.message}`);
@@ -554,23 +610,66 @@ function statusToHint(status: TypeStatus): string | undefined {
554
610
  }
555
611
 
556
612
  // Slices Section
613
+ function sliceHasFields(slice: SharedSlice): boolean {
614
+ for (const variation of slice.variations) {
615
+ const primaryFields = Object.keys(variation.primary ?? {});
616
+ const itemFields = Object.keys(variation.items ?? {});
617
+ if (primaryFields.length > 0 || itemFields.length > 0) {
618
+ return true;
619
+ }
620
+ }
621
+ return false;
622
+ }
623
+
624
+ function isSliceConnectedToAnyType(sliceId: string, localTypes: CustomType[]): boolean {
625
+ for (const type of localTypes) {
626
+ for (const tabFields of Object.values(type.json)) {
627
+ for (const field of Object.values(tabFields as Record<string, unknown>)) {
628
+ const typedField = field as {
629
+ type?: string;
630
+ config?: { choices?: Record<string, unknown> };
631
+ };
632
+ if (typedField.type === "Slices" && typedField.config?.choices?.[sliceId]) {
633
+ return true;
634
+ }
635
+ }
636
+ }
637
+ }
638
+ return false;
639
+ }
640
+
557
641
  async function buildSlicesSection(
558
642
  localSlices: SharedSlice[],
559
643
  remoteSlices: SharedSlice[],
560
644
  info: FrameworkInfo,
645
+ localTypes: CustomType[],
561
646
  ): Promise<{
562
647
  section: StatusSection;
563
648
  statuses: TypeWithStatus[];
564
649
  missingComponents: string[];
650
+ slicesReadyToConnect: string[];
565
651
  }> {
566
652
  const sliceStatuses = computeTypeStatus(localSlices, remoteSlices);
567
653
  const items: StatusItem[] = [];
568
654
  const missingComponents: string[] = [];
655
+ const slicesReadyToConnect: string[] = [];
569
656
 
570
657
  const slicesDir = getSlicesDirectory(info);
571
658
  const extensions = getSliceComponentExtensions(info.framework);
572
659
 
573
660
  for (const slice of sliceStatuses) {
661
+ const localSlice = localSlices.find((s) => s.id === slice.id);
662
+
663
+ // Track slices that have fields but aren't connected to any type
664
+ // These should be connected before pushing
665
+ if (localSlice) {
666
+ const hasFields = sliceHasFields(localSlice);
667
+ const isConnected = isSliceConnectedToAnyType(slice.id, localTypes);
668
+
669
+ if (hasFields && !isConnected) {
670
+ slicesReadyToConnect.push(slice.label);
671
+ }
672
+ }
574
673
  // Check if component is implemented
575
674
  const componentExists = await checkSliceComponent(info, slicesDir, slice.id, extensions);
576
675
 
@@ -600,6 +699,7 @@ async function buildSlicesSection(
600
699
  section: { title: "Slices", items },
601
700
  statuses: sliceStatuses,
602
701
  missingComponents,
702
+ slicesReadyToConnect,
603
703
  };
604
704
  }
605
705