@angeloashmore/prismic-cli-poc 0.0.0-pr.3.219652e → 0.0.0-pr.4.484acb8
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.mjs +99 -96
- package/package.json +1 -1
- package/src/custom-type-add-field-boolean.ts +4 -0
- package/src/custom-type-add-field-color.ts +4 -0
- package/src/custom-type-add-field-date.ts +4 -0
- package/src/custom-type-add-field-embed.ts +4 -0
- package/src/custom-type-add-field-geo-point.ts +4 -0
- package/src/custom-type-add-field-image.ts +4 -0
- package/src/custom-type-add-field-key-text.ts +4 -0
- package/src/custom-type-add-field-link.ts +4 -0
- package/src/custom-type-add-field-number.ts +4 -0
- package/src/custom-type-add-field-rich-text.ts +4 -0
- package/src/custom-type-add-field-select.ts +4 -0
- package/src/custom-type-add-field-timestamp.ts +4 -0
- package/src/custom-type-add-field-uid.ts +4 -0
- package/src/custom-type-create.ts +3 -0
- package/src/page-type-add-field-boolean.ts +4 -0
- package/src/page-type-add-field-color.ts +4 -0
- package/src/page-type-add-field-date.ts +4 -0
- package/src/page-type-add-field-embed.ts +4 -0
- package/src/page-type-add-field-geo-point.ts +4 -0
- package/src/page-type-add-field-image.ts +4 -0
- package/src/page-type-add-field-key-text.ts +4 -0
- package/src/page-type-add-field-link.ts +4 -0
- package/src/page-type-add-field-number.ts +4 -0
- package/src/page-type-add-field-rich-text.ts +4 -0
- package/src/page-type-add-field-select.ts +4 -0
- package/src/page-type-add-field-timestamp.ts +4 -0
- package/src/page-type-add-field-uid.ts +4 -0
- package/src/page-type-create.ts +3 -0
- package/src/slice-add-field-boolean.ts +4 -0
- package/src/slice-add-field-color.ts +4 -0
- package/src/slice-add-field-date.ts +4 -0
- package/src/slice-add-field-embed.ts +4 -0
- package/src/slice-add-field-geo-point.ts +4 -0
- package/src/slice-add-field-image.ts +4 -0
- package/src/slice-add-field-key-text.ts +4 -0
- package/src/slice-add-field-link.ts +4 -0
- package/src/slice-add-field-number.ts +4 -0
- package/src/slice-add-field-rich-text.ts +4 -0
- package/src/slice-add-field-select.ts +4 -0
- package/src/slice-add-field-timestamp.ts +4 -0
- package/src/slice-create.ts +3 -0
- package/src/status.ts +176 -31
package/src/status.ts
CHANGED
|
@@ -14,6 +14,7 @@ import {
|
|
|
14
14
|
} from "./lib/custom-types-api";
|
|
15
15
|
import { exists } from "./lib/file";
|
|
16
16
|
import {
|
|
17
|
+
type Framework,
|
|
17
18
|
type FrameworkInfo,
|
|
18
19
|
detectFrameworkInfo,
|
|
19
20
|
getClientFilePath,
|
|
@@ -29,6 +30,9 @@ import { getWebhooks } from "./webhook-view";
|
|
|
29
30
|
const HELP = `
|
|
30
31
|
Show the status of the current Prismic project.
|
|
31
32
|
|
|
33
|
+
Includes a "Next:" step showing the most important action to take based on
|
|
34
|
+
project state.
|
|
35
|
+
|
|
32
36
|
By default, this command reads the repository from prismic.config.json at the
|
|
33
37
|
project root.
|
|
34
38
|
|
|
@@ -58,6 +62,135 @@ type StatusSection = {
|
|
|
58
62
|
items: StatusItem[];
|
|
59
63
|
};
|
|
60
64
|
|
|
65
|
+
type NextStep = {
|
|
66
|
+
message: string;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
function getDocsUrl(framework: Framework | undefined): string {
|
|
70
|
+
switch (framework) {
|
|
71
|
+
case "next":
|
|
72
|
+
return "https://prismic.io/docs/nextjs/with-cli";
|
|
73
|
+
case "nuxt":
|
|
74
|
+
return "https://prismic.io/docs/nuxt/with-cli";
|
|
75
|
+
case "sveltekit":
|
|
76
|
+
return "https://prismic.io/docs/sveltekit/with-cli";
|
|
77
|
+
default:
|
|
78
|
+
return "https://prismic.io/docs";
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function computeNextStep(
|
|
83
|
+
sections: StatusSection[],
|
|
84
|
+
frameworkInfo: FrameworkInfo,
|
|
85
|
+
typeStatuses: TypeWithStatus[],
|
|
86
|
+
sliceStatuses: TypeWithStatus[],
|
|
87
|
+
slicesWithMissingComponents: string[],
|
|
88
|
+
): NextStep | undefined {
|
|
89
|
+
const docsUrl = getDocsUrl(frameworkInfo.framework);
|
|
90
|
+
|
|
91
|
+
// 1. Setup - missing dependencies
|
|
92
|
+
const setupSection = sections.find((s) => s.title === "Setup");
|
|
93
|
+
const missingDeps = setupSection?.items.filter((i) => !i.done && i.hint === "not installed");
|
|
94
|
+
if (missingDeps && missingDeps.length > 0) {
|
|
95
|
+
const depsList = missingDeps.map((d) => d.label).join(" ");
|
|
96
|
+
return { message: `Install Prismic packages with 'npm install ${depsList}'` };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// 2. Setup - missing client file
|
|
100
|
+
const missingClientFile = setupSection?.items.find((i) => !i.done && i.hint?.includes("client"));
|
|
101
|
+
if (missingClientFile) {
|
|
102
|
+
return { message: `Create a ${missingClientFile.label} file (see ${docsUrl})` };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// 3-7. Preview section (in order: local files, then remote config)
|
|
106
|
+
const previewSection = sections.find((s) => s.title === "Preview");
|
|
107
|
+
if (previewSection) {
|
|
108
|
+
// Local files first
|
|
109
|
+
const sliceSimRoute = previewSection.items.find(
|
|
110
|
+
(i) => i.label === "/slice-simulator route" && !i.done,
|
|
111
|
+
);
|
|
112
|
+
if (sliceSimRoute) {
|
|
113
|
+
return { message: `Create the /slice-simulator route (see ${docsUrl})` };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const apiPreview = previewSection.items.find(
|
|
117
|
+
(i) => i.label === "/api/preview endpoint" && !i.done,
|
|
118
|
+
);
|
|
119
|
+
if (apiPreview) {
|
|
120
|
+
return { message: `Create the /api/preview route (see ${docsUrl})` };
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const exitPreview = previewSection.items.find(
|
|
124
|
+
(i) => i.label === "/api/exit-preview endpoint" && !i.done,
|
|
125
|
+
);
|
|
126
|
+
if (exitPreview) {
|
|
127
|
+
return { message: `Create the /api/exit-preview route (see ${docsUrl})` };
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Remote config
|
|
131
|
+
const simulatorUrl = previewSection.items.find(
|
|
132
|
+
(i) => i.label === "Slice simulator URL" && !i.done,
|
|
133
|
+
);
|
|
134
|
+
if (simulatorUrl) {
|
|
135
|
+
return { message: `Configure the slice simulator URL with 'prismic preview set-simulator'` };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const previewEnv = previewSection.items.find(
|
|
139
|
+
(i) => i.label === "Preview environment" && !i.done,
|
|
140
|
+
);
|
|
141
|
+
if (previewEnv) {
|
|
142
|
+
return { message: `Add a preview environment with 'prismic preview add'` };
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
// 8. Models to pull
|
|
147
|
+
const hasToPull =
|
|
148
|
+
typeStatuses.some((t) => t.status === "to_pull") ||
|
|
149
|
+
sliceStatuses.some((s) => s.status === "to_pull");
|
|
150
|
+
if (hasToPull) {
|
|
151
|
+
return { message: `Pull remote models with 'prismic pull'` };
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// 9. Models to push
|
|
155
|
+
const hasToPush =
|
|
156
|
+
typeStatuses.some((t) => t.status === "to_push") ||
|
|
157
|
+
sliceStatuses.some((s) => s.status === "to_push");
|
|
158
|
+
if (hasToPush) {
|
|
159
|
+
return { message: `Push local models with 'prismic push'` };
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// 10. Slice components to implement (first alphabetically)
|
|
163
|
+
if (slicesWithMissingComponents.length > 0) {
|
|
164
|
+
const sorted = [...slicesWithMissingComponents].sort();
|
|
165
|
+
const sliceName = sorted[0];
|
|
166
|
+
const slicesDir = getSlicesDirectory(frameworkInfo);
|
|
167
|
+
const ext = getSliceComponentExtensions(frameworkInfo.framework)[0];
|
|
168
|
+
const path = `${slicesDir}${sliceName}/index${ext}`;
|
|
169
|
+
return { message: `Implement the ${sliceName} slice component at ${path} (see ${docsUrl})` };
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// 11-12. Deployment (Next.js only)
|
|
173
|
+
const deploymentSection = sections.find((s) => s.title === "Deployment");
|
|
174
|
+
if (deploymentSection) {
|
|
175
|
+
const revalidateEndpoint = deploymentSection.items.find(
|
|
176
|
+
(i) => i.label === "/api/revalidate endpoint" && !i.done,
|
|
177
|
+
);
|
|
178
|
+
if (revalidateEndpoint) {
|
|
179
|
+
return { message: `Create the /api/revalidate route for ISR (see ${docsUrl})` };
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
const webhook = deploymentSection.items.find(
|
|
183
|
+
(i) => i.label === "Revalidation webhook" && !i.done,
|
|
184
|
+
);
|
|
185
|
+
if (webhook) {
|
|
186
|
+
return { message: `Create a revalidation webhook with 'prismic webhook create'` };
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// All complete
|
|
191
|
+
return undefined;
|
|
192
|
+
}
|
|
193
|
+
|
|
61
194
|
export async function status(): Promise<void> {
|
|
62
195
|
const {
|
|
63
196
|
values: { help, repo = await safeGetRepositoryFromConfig() },
|
|
@@ -118,39 +251,42 @@ export async function status(): Promise<void> {
|
|
|
118
251
|
|
|
119
252
|
// Print repository header
|
|
120
253
|
const repoUrl = await getRepoUrl(repo);
|
|
121
|
-
console.info(`Repository:
|
|
122
|
-
console.info(`URL:
|
|
123
|
-
|
|
124
|
-
if (repoInfoResult.ok) {
|
|
125
|
-
const accessLevel = formatApiAccess(repoInfoResult.value.api_access);
|
|
126
|
-
console.info(`Content API Access: ${accessLevel}`);
|
|
127
|
-
}
|
|
254
|
+
console.info(`Repository: ${repo}`);
|
|
255
|
+
console.info(`URL: ${repoUrl.href}`);
|
|
128
256
|
console.info("");
|
|
129
257
|
|
|
130
258
|
const sections: StatusSection[] = [];
|
|
131
259
|
|
|
260
|
+
// Track statuses for next step computation
|
|
261
|
+
let typeStatuses: TypeWithStatus[] = [];
|
|
262
|
+
let sliceStatuses: TypeWithStatus[] = [];
|
|
263
|
+
let slicesWithMissingComponents: string[] = [];
|
|
264
|
+
|
|
132
265
|
// Setup section
|
|
133
266
|
const setupSection = await buildSetupSection(frameworkInfo, installedDeps);
|
|
134
267
|
sections.push(setupSection);
|
|
135
268
|
|
|
136
269
|
// Types sections (Page Types and Custom Types)
|
|
137
270
|
if (localTypesResult.ok && remoteTypesResult.ok) {
|
|
138
|
-
const { pageTypes, customTypes } = buildTypeSections(
|
|
271
|
+
const { pageTypes, customTypes, allTypeStatuses } = buildTypeSections(
|
|
139
272
|
localTypesResult.value,
|
|
140
273
|
remoteTypesResult.value,
|
|
141
274
|
);
|
|
142
275
|
sections.push(pageTypes);
|
|
143
276
|
sections.push(customTypes);
|
|
277
|
+
typeStatuses = allTypeStatuses;
|
|
144
278
|
}
|
|
145
279
|
|
|
146
280
|
// Slices section
|
|
147
281
|
if (localSlicesResult.ok && remoteSlicesResult.ok) {
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
);
|
|
282
|
+
const {
|
|
283
|
+
section: slicesSection,
|
|
284
|
+
statuses,
|
|
285
|
+
missingComponents,
|
|
286
|
+
} = await buildSlicesSection(localSlicesResult.value, remoteSlicesResult.value, frameworkInfo);
|
|
153
287
|
sections.push(slicesSection);
|
|
288
|
+
sliceStatuses = statuses;
|
|
289
|
+
slicesWithMissingComponents = missingComponents;
|
|
154
290
|
}
|
|
155
291
|
|
|
156
292
|
// Preview section
|
|
@@ -174,6 +310,18 @@ export async function status(): Promise<void> {
|
|
|
174
310
|
for (const section of sections) {
|
|
175
311
|
printSection(section);
|
|
176
312
|
}
|
|
313
|
+
|
|
314
|
+
// Print next step
|
|
315
|
+
const nextStep = computeNextStep(
|
|
316
|
+
sections,
|
|
317
|
+
frameworkInfo,
|
|
318
|
+
typeStatuses,
|
|
319
|
+
sliceStatuses,
|
|
320
|
+
slicesWithMissingComponents,
|
|
321
|
+
);
|
|
322
|
+
if (nextStep) {
|
|
323
|
+
console.info(`Next: ${nextStep.message}`);
|
|
324
|
+
}
|
|
177
325
|
}
|
|
178
326
|
|
|
179
327
|
function printSection(section: StatusSection): void {
|
|
@@ -208,9 +356,8 @@ function printSection(section: StatusSection): void {
|
|
|
208
356
|
console.info("");
|
|
209
357
|
}
|
|
210
358
|
|
|
211
|
-
// Repository Info
|
|
359
|
+
// Repository Info (from /core/repository)
|
|
212
360
|
const RepositoryInfoSchema = v.object({
|
|
213
|
-
api_access: v.optional(v.string()),
|
|
214
361
|
simulator_url: v.optional(v.string()),
|
|
215
362
|
});
|
|
216
363
|
type RepositoryInfo = v.InferOutput<typeof RepositoryInfoSchema>;
|
|
@@ -226,19 +373,6 @@ async function fetchRepositoryInfo(
|
|
|
226
373
|
return { ok: false };
|
|
227
374
|
}
|
|
228
375
|
|
|
229
|
-
function formatApiAccess(access: string | undefined): string {
|
|
230
|
-
switch (access) {
|
|
231
|
-
case "private":
|
|
232
|
-
return "Private";
|
|
233
|
-
case "open":
|
|
234
|
-
return "Open";
|
|
235
|
-
case "master_only":
|
|
236
|
-
return "Master only";
|
|
237
|
-
default:
|
|
238
|
-
return access || "Unknown";
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
|
|
242
376
|
// Previews
|
|
243
377
|
const PreviewSchema = v.object({
|
|
244
378
|
id: v.string(),
|
|
@@ -371,7 +505,7 @@ function computeTypeStatus<T extends { id: string }>(local: T[], remote: T[]): T
|
|
|
371
505
|
function buildTypeSections(
|
|
372
506
|
localTypes: CustomType[],
|
|
373
507
|
remoteTypes: CustomType[],
|
|
374
|
-
): { pageTypes: StatusSection; customTypes: StatusSection } {
|
|
508
|
+
): { pageTypes: StatusSection; customTypes: StatusSection; allTypeStatuses: TypeWithStatus[] } {
|
|
375
509
|
const typeStatuses = computeTypeStatus(localTypes, remoteTypes);
|
|
376
510
|
|
|
377
511
|
// Separate by format
|
|
@@ -404,6 +538,7 @@ function buildTypeSections(
|
|
|
404
538
|
return {
|
|
405
539
|
pageTypes: { title: "Page Types", items: pageTypeItems },
|
|
406
540
|
customTypes: { title: "Custom Types", items: customTypeItems },
|
|
541
|
+
allTypeStatuses: typeStatuses,
|
|
407
542
|
};
|
|
408
543
|
}
|
|
409
544
|
|
|
@@ -423,9 +558,14 @@ async function buildSlicesSection(
|
|
|
423
558
|
localSlices: SharedSlice[],
|
|
424
559
|
remoteSlices: SharedSlice[],
|
|
425
560
|
info: FrameworkInfo,
|
|
426
|
-
): Promise<
|
|
561
|
+
): Promise<{
|
|
562
|
+
section: StatusSection;
|
|
563
|
+
statuses: TypeWithStatus[];
|
|
564
|
+
missingComponents: string[];
|
|
565
|
+
}> {
|
|
427
566
|
const sliceStatuses = computeTypeStatus(localSlices, remoteSlices);
|
|
428
567
|
const items: StatusItem[] = [];
|
|
568
|
+
const missingComponents: string[] = [];
|
|
429
569
|
|
|
430
570
|
const slicesDir = getSlicesDirectory(info);
|
|
431
571
|
const extensions = getSliceComponentExtensions(info.framework);
|
|
@@ -446,6 +586,7 @@ async function buildSlicesSection(
|
|
|
446
586
|
label: slice.label,
|
|
447
587
|
hint: "missing component",
|
|
448
588
|
});
|
|
589
|
+
missingComponents.push(slice.label);
|
|
449
590
|
} else {
|
|
450
591
|
items.push({
|
|
451
592
|
done: false,
|
|
@@ -455,7 +596,11 @@ async function buildSlicesSection(
|
|
|
455
596
|
}
|
|
456
597
|
}
|
|
457
598
|
|
|
458
|
-
return {
|
|
599
|
+
return {
|
|
600
|
+
section: { title: "Slices", items },
|
|
601
|
+
statuses: sliceStatuses,
|
|
602
|
+
missingComponents,
|
|
603
|
+
};
|
|
459
604
|
}
|
|
460
605
|
|
|
461
606
|
async function checkSliceComponent(
|