@angeloashmore/prismic-cli-poc 0.0.0-pr.4.d609497 → 0.0.0-pr.5.f8fb51a
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 +152 -130
- package/package.json +1 -1
- package/src/docs.ts +149 -0
- package/src/index.ts +5 -0
- package/src/status.ts +213 -31
package/package.json
CHANGED
package/src/docs.ts
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { parseArgs } from "node:util";
|
|
2
|
+
|
|
3
|
+
const HELP = `
|
|
4
|
+
Fetch and display documentation from Prismic's docs site.
|
|
5
|
+
|
|
6
|
+
USAGE
|
|
7
|
+
prismic docs <path> [flags]
|
|
8
|
+
|
|
9
|
+
ARGUMENTS
|
|
10
|
+
path Documentation path with optional anchor (e.g., "nextjs" or "nextjs#set-up-a-prismic-client")
|
|
11
|
+
|
|
12
|
+
FLAGS
|
|
13
|
+
-h, --help Show help for command
|
|
14
|
+
|
|
15
|
+
EXAMPLES
|
|
16
|
+
prismic docs nextjs
|
|
17
|
+
prismic docs nextjs#set-up-a-prismic-client
|
|
18
|
+
|
|
19
|
+
LEARN MORE
|
|
20
|
+
Visit https://prismic.io/docs for the full documentation.
|
|
21
|
+
`.trim();
|
|
22
|
+
|
|
23
|
+
function parsePathAndAnchor(input: string): { path: string; anchor?: string } {
|
|
24
|
+
const hashIndex = input.indexOf("#");
|
|
25
|
+
if (hashIndex === -1) {
|
|
26
|
+
return { path: input };
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
path: input.slice(0, hashIndex),
|
|
30
|
+
anchor: input.slice(hashIndex + 1),
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async function fetchMarkdown(
|
|
35
|
+
url: string,
|
|
36
|
+
): Promise<{ ok: true; content: string } | { ok: false; error: string }> {
|
|
37
|
+
try {
|
|
38
|
+
const response = await fetch(url);
|
|
39
|
+
if (response.status === 404) {
|
|
40
|
+
return { ok: false, error: `Documentation not found: ${url}` };
|
|
41
|
+
}
|
|
42
|
+
if (!response.ok) {
|
|
43
|
+
return {
|
|
44
|
+
ok: false,
|
|
45
|
+
error: `Failed to fetch documentation: ${response.status}`,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
const content = await response.text();
|
|
49
|
+
return { ok: true, content };
|
|
50
|
+
} catch (error) {
|
|
51
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
52
|
+
return { ok: false, error: `Network error: ${message}` };
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function anchorToHeadingPattern(anchor: string): RegExp {
|
|
57
|
+
// Convert kebab-case anchor to a pattern that matches the heading text
|
|
58
|
+
// Each hyphen/space becomes a flexible match for hyphens or spaces
|
|
59
|
+
const pattern = anchor
|
|
60
|
+
.split("-")
|
|
61
|
+
.map((word) => word.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"))
|
|
62
|
+
.join("[\\s-]+");
|
|
63
|
+
return new RegExp(`^(#{1,6})\\s+${pattern}\\s*$`, "im");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function extractSection(
|
|
67
|
+
markdown: string,
|
|
68
|
+
anchor: string,
|
|
69
|
+
): { ok: true; content: string } | { ok: false; error: string } {
|
|
70
|
+
const lines = markdown.split("\n");
|
|
71
|
+
const headingPattern = anchorToHeadingPattern(anchor);
|
|
72
|
+
|
|
73
|
+
let startIndex = -1;
|
|
74
|
+
let headingLevel = 0;
|
|
75
|
+
|
|
76
|
+
// Find the matching heading
|
|
77
|
+
for (let i = 0; i < lines.length; i++) {
|
|
78
|
+
const match = lines[i].match(headingPattern);
|
|
79
|
+
if (match) {
|
|
80
|
+
startIndex = i;
|
|
81
|
+
headingLevel = match[1].length;
|
|
82
|
+
break;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (startIndex === -1) {
|
|
87
|
+
return { ok: false, error: `Anchor not found: #${anchor}` };
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Find the end of this section (next heading of equal or lower level number)
|
|
91
|
+
let endIndex = lines.length;
|
|
92
|
+
for (let i = startIndex + 1; i < lines.length; i++) {
|
|
93
|
+
const headingMatch = lines[i].match(/^(#{1,6})\s/);
|
|
94
|
+
if (headingMatch && headingMatch[1].length <= headingLevel) {
|
|
95
|
+
endIndex = i;
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const content = lines.slice(startIndex, endIndex).join("\n").trim();
|
|
101
|
+
return { ok: true, content };
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export async function docs(): Promise<void> {
|
|
105
|
+
const {
|
|
106
|
+
positionals: [pathArg],
|
|
107
|
+
values: { help },
|
|
108
|
+
} = parseArgs({
|
|
109
|
+
args: process.argv.slice(3),
|
|
110
|
+
options: {
|
|
111
|
+
help: { type: "boolean", short: "h" },
|
|
112
|
+
},
|
|
113
|
+
allowPositionals: true,
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
if (help) {
|
|
117
|
+
console.info(HELP);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (!pathArg) {
|
|
122
|
+
console.info(HELP);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const { path, anchor } = parsePathAndAnchor(pathArg);
|
|
127
|
+
const url = `https://prismic.io/docs/${path}.md`;
|
|
128
|
+
|
|
129
|
+
const fetchResult = await fetchMarkdown(url);
|
|
130
|
+
if (!fetchResult.ok) {
|
|
131
|
+
console.error(fetchResult.error);
|
|
132
|
+
process.exitCode = 1;
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
let output = fetchResult.content;
|
|
137
|
+
|
|
138
|
+
if (anchor) {
|
|
139
|
+
const extractResult = extractSection(output, anchor);
|
|
140
|
+
if (!extractResult.ok) {
|
|
141
|
+
console.error(extractResult.error);
|
|
142
|
+
process.exitCode = 1;
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
output = extractResult.content;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
console.info(output);
|
|
149
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { parseArgs } from "node:util";
|
|
|
5
5
|
import packageJson from "../package.json" with { type: "json" };
|
|
6
6
|
import { codegen } from "./codegen";
|
|
7
7
|
import { customType } from "./custom-type";
|
|
8
|
+
import { docs } from "./docs";
|
|
8
9
|
import { init } from "./init";
|
|
9
10
|
import { locale } from "./locale";
|
|
10
11
|
import { login } from "./login";
|
|
@@ -40,6 +41,7 @@ COMMANDS
|
|
|
40
41
|
pull Pull types and slices from Prismic
|
|
41
42
|
push Push types and slices to Prismic
|
|
42
43
|
codegen Generate code from Prismic models
|
|
44
|
+
docs Fetch documentation from Prismic
|
|
43
45
|
preview Manage preview configurations
|
|
44
46
|
token Manage API tokens in a repository
|
|
45
47
|
webhook Manage webhooks in a repository
|
|
@@ -107,6 +109,9 @@ if (version) {
|
|
|
107
109
|
case "codegen":
|
|
108
110
|
await codegen();
|
|
109
111
|
break;
|
|
112
|
+
case "docs":
|
|
113
|
+
await docs();
|
|
114
|
+
break;
|
|
110
115
|
case "preview":
|
|
111
116
|
await preview();
|
|
112
117
|
break;
|
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,172 @@ type StatusSection = {
|
|
|
58
62
|
items: StatusItem[];
|
|
59
63
|
};
|
|
60
64
|
|
|
65
|
+
type NextStep = {
|
|
66
|
+
message: string;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
function getDocsPath(framework: Framework | undefined): string {
|
|
70
|
+
switch (framework) {
|
|
71
|
+
case "next":
|
|
72
|
+
return "nextjs/with-cli";
|
|
73
|
+
case "nuxt":
|
|
74
|
+
return "nuxt/with-cli";
|
|
75
|
+
case "sveltekit":
|
|
76
|
+
return "sveltekit/with-cli";
|
|
77
|
+
default:
|
|
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";
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function computeNextStep(
|
|
120
|
+
sections: StatusSection[],
|
|
121
|
+
frameworkInfo: FrameworkInfo,
|
|
122
|
+
typeStatuses: TypeWithStatus[],
|
|
123
|
+
sliceStatuses: TypeWithStatus[],
|
|
124
|
+
slicesWithMissingComponents: string[],
|
|
125
|
+
): NextStep | undefined {
|
|
126
|
+
const docsPath = getDocsPath(frameworkInfo.framework);
|
|
127
|
+
|
|
128
|
+
// 1. Setup - missing dependencies
|
|
129
|
+
const setupSection = sections.find((s) => s.title === "Setup");
|
|
130
|
+
const missingDeps = setupSection?.items.filter((i) => !i.done && i.hint === "not installed");
|
|
131
|
+
if (missingDeps && missingDeps.length > 0) {
|
|
132
|
+
const depsList = missingDeps.map((d) => d.label).join(" ");
|
|
133
|
+
return { message: `Install Prismic packages with 'npm install ${depsList}'` };
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// 2. Setup - missing client file
|
|
137
|
+
const missingClientFile = setupSection?.items.find((i) => !i.done && i.hint?.includes("client"));
|
|
138
|
+
if (missingClientFile) {
|
|
139
|
+
return { message: `Create a ${missingClientFile.label} file${getDocsRef(docsPath, getClientSetupAnchor(frameworkInfo.framework))}` };
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// 3-7. Preview section (in order: local files, then remote config)
|
|
143
|
+
const previewSection = sections.find((s) => s.title === "Preview");
|
|
144
|
+
if (previewSection) {
|
|
145
|
+
// Local files first
|
|
146
|
+
const sliceSimRoute = previewSection.items.find(
|
|
147
|
+
(i) => i.label === "/slice-simulator route" && !i.done,
|
|
148
|
+
);
|
|
149
|
+
if (sliceSimRoute) {
|
|
150
|
+
return { message: `Create the /slice-simulator route${getDocsRef(docsPath, "#set-up-live-previewing")}` };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const apiPreview = previewSection.items.find(
|
|
154
|
+
(i) => i.label === "/api/preview endpoint" && !i.done,
|
|
155
|
+
);
|
|
156
|
+
if (apiPreview) {
|
|
157
|
+
return { message: `Create the /api/preview route${getDocsRef(docsPath, getPreviewSetupAnchor(frameworkInfo.framework))}` };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const exitPreview = previewSection.items.find(
|
|
161
|
+
(i) => i.label === "/api/exit-preview endpoint" && !i.done,
|
|
162
|
+
);
|
|
163
|
+
if (exitPreview) {
|
|
164
|
+
return { message: `Create the /api/exit-preview route${getDocsRef(docsPath, getPreviewSetupAnchor(frameworkInfo.framework))}` };
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Remote config
|
|
168
|
+
const simulatorUrl = previewSection.items.find(
|
|
169
|
+
(i) => i.label === "Slice simulator URL" && !i.done,
|
|
170
|
+
);
|
|
171
|
+
if (simulatorUrl) {
|
|
172
|
+
return { message: `Configure the slice simulator URL with 'prismic preview set-simulator'` };
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const previewEnv = previewSection.items.find(
|
|
176
|
+
(i) => i.label === "Preview environment" && !i.done,
|
|
177
|
+
);
|
|
178
|
+
if (previewEnv) {
|
|
179
|
+
return { message: `Add a preview environment with 'prismic preview add'` };
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// 8. Models to pull
|
|
184
|
+
const hasToPull =
|
|
185
|
+
typeStatuses.some((t) => t.status === "to_pull") ||
|
|
186
|
+
sliceStatuses.some((s) => s.status === "to_pull");
|
|
187
|
+
if (hasToPull) {
|
|
188
|
+
return { message: `Pull remote models with 'prismic pull'` };
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// 9. Models to push
|
|
192
|
+
const hasToPush =
|
|
193
|
+
typeStatuses.some((t) => t.status === "to_push") ||
|
|
194
|
+
sliceStatuses.some((s) => s.status === "to_push");
|
|
195
|
+
if (hasToPush) {
|
|
196
|
+
return { message: `Push local models with 'prismic push'` };
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// 10. Slice components to implement (first alphabetically)
|
|
200
|
+
if (slicesWithMissingComponents.length > 0) {
|
|
201
|
+
const sorted = [...slicesWithMissingComponents].sort();
|
|
202
|
+
const sliceName = sorted[0];
|
|
203
|
+
const slicesDir = getSlicesDirectory(frameworkInfo);
|
|
204
|
+
const ext = getSliceComponentExtensions(frameworkInfo.framework)[0];
|
|
205
|
+
const path = `${slicesDir}${sliceName}/index${ext}`;
|
|
206
|
+
return { message: `Implement the ${sliceName} slice component at ${path}${getDocsRef(docsPath, getWriteComponentsAnchor(frameworkInfo.framework))}` };
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// 11-12. Deployment (Next.js only)
|
|
210
|
+
const deploymentSection = sections.find((s) => s.title === "Deployment");
|
|
211
|
+
if (deploymentSection) {
|
|
212
|
+
const revalidateEndpoint = deploymentSection.items.find(
|
|
213
|
+
(i) => i.label === "/api/revalidate endpoint" && !i.done,
|
|
214
|
+
);
|
|
215
|
+
if (revalidateEndpoint) {
|
|
216
|
+
return { message: `Create the /api/revalidate route for ISR${getDocsRef(docsPath, "#handle-content-changes")}` };
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const webhook = deploymentSection.items.find(
|
|
220
|
+
(i) => i.label === "Revalidation webhook" && !i.done,
|
|
221
|
+
);
|
|
222
|
+
if (webhook) {
|
|
223
|
+
return { message: `Create a revalidation webhook with 'prismic webhook create'` };
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// All complete
|
|
228
|
+
return undefined;
|
|
229
|
+
}
|
|
230
|
+
|
|
61
231
|
export async function status(): Promise<void> {
|
|
62
232
|
const {
|
|
63
233
|
values: { help, repo = await safeGetRepositoryFromConfig() },
|
|
@@ -118,39 +288,42 @@ export async function status(): Promise<void> {
|
|
|
118
288
|
|
|
119
289
|
// Print repository header
|
|
120
290
|
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
|
-
}
|
|
291
|
+
console.info(`Repository: ${repo}`);
|
|
292
|
+
console.info(`URL: ${repoUrl.href}`);
|
|
128
293
|
console.info("");
|
|
129
294
|
|
|
130
295
|
const sections: StatusSection[] = [];
|
|
131
296
|
|
|
297
|
+
// Track statuses for next step computation
|
|
298
|
+
let typeStatuses: TypeWithStatus[] = [];
|
|
299
|
+
let sliceStatuses: TypeWithStatus[] = [];
|
|
300
|
+
let slicesWithMissingComponents: string[] = [];
|
|
301
|
+
|
|
132
302
|
// Setup section
|
|
133
303
|
const setupSection = await buildSetupSection(frameworkInfo, installedDeps);
|
|
134
304
|
sections.push(setupSection);
|
|
135
305
|
|
|
136
306
|
// Types sections (Page Types and Custom Types)
|
|
137
307
|
if (localTypesResult.ok && remoteTypesResult.ok) {
|
|
138
|
-
const { pageTypes, customTypes } = buildTypeSections(
|
|
308
|
+
const { pageTypes, customTypes, allTypeStatuses } = buildTypeSections(
|
|
139
309
|
localTypesResult.value,
|
|
140
310
|
remoteTypesResult.value,
|
|
141
311
|
);
|
|
142
312
|
sections.push(pageTypes);
|
|
143
313
|
sections.push(customTypes);
|
|
314
|
+
typeStatuses = allTypeStatuses;
|
|
144
315
|
}
|
|
145
316
|
|
|
146
317
|
// Slices section
|
|
147
318
|
if (localSlicesResult.ok && remoteSlicesResult.ok) {
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
);
|
|
319
|
+
const {
|
|
320
|
+
section: slicesSection,
|
|
321
|
+
statuses,
|
|
322
|
+
missingComponents,
|
|
323
|
+
} = await buildSlicesSection(localSlicesResult.value, remoteSlicesResult.value, frameworkInfo);
|
|
153
324
|
sections.push(slicesSection);
|
|
325
|
+
sliceStatuses = statuses;
|
|
326
|
+
slicesWithMissingComponents = missingComponents;
|
|
154
327
|
}
|
|
155
328
|
|
|
156
329
|
// Preview section
|
|
@@ -174,6 +347,18 @@ export async function status(): Promise<void> {
|
|
|
174
347
|
for (const section of sections) {
|
|
175
348
|
printSection(section);
|
|
176
349
|
}
|
|
350
|
+
|
|
351
|
+
// Print next step
|
|
352
|
+
const nextStep = computeNextStep(
|
|
353
|
+
sections,
|
|
354
|
+
frameworkInfo,
|
|
355
|
+
typeStatuses,
|
|
356
|
+
sliceStatuses,
|
|
357
|
+
slicesWithMissingComponents,
|
|
358
|
+
);
|
|
359
|
+
if (nextStep) {
|
|
360
|
+
console.info(`Next: ${nextStep.message}`);
|
|
361
|
+
}
|
|
177
362
|
}
|
|
178
363
|
|
|
179
364
|
function printSection(section: StatusSection): void {
|
|
@@ -208,9 +393,8 @@ function printSection(section: StatusSection): void {
|
|
|
208
393
|
console.info("");
|
|
209
394
|
}
|
|
210
395
|
|
|
211
|
-
// Repository Info
|
|
396
|
+
// Repository Info (from /core/repository)
|
|
212
397
|
const RepositoryInfoSchema = v.object({
|
|
213
|
-
api_access: v.optional(v.string()),
|
|
214
398
|
simulator_url: v.optional(v.string()),
|
|
215
399
|
});
|
|
216
400
|
type RepositoryInfo = v.InferOutput<typeof RepositoryInfoSchema>;
|
|
@@ -226,19 +410,6 @@ async function fetchRepositoryInfo(
|
|
|
226
410
|
return { ok: false };
|
|
227
411
|
}
|
|
228
412
|
|
|
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
413
|
// Previews
|
|
243
414
|
const PreviewSchema = v.object({
|
|
244
415
|
id: v.string(),
|
|
@@ -371,7 +542,7 @@ function computeTypeStatus<T extends { id: string }>(local: T[], remote: T[]): T
|
|
|
371
542
|
function buildTypeSections(
|
|
372
543
|
localTypes: CustomType[],
|
|
373
544
|
remoteTypes: CustomType[],
|
|
374
|
-
): { pageTypes: StatusSection; customTypes: StatusSection } {
|
|
545
|
+
): { pageTypes: StatusSection; customTypes: StatusSection; allTypeStatuses: TypeWithStatus[] } {
|
|
375
546
|
const typeStatuses = computeTypeStatus(localTypes, remoteTypes);
|
|
376
547
|
|
|
377
548
|
// Separate by format
|
|
@@ -404,6 +575,7 @@ function buildTypeSections(
|
|
|
404
575
|
return {
|
|
405
576
|
pageTypes: { title: "Page Types", items: pageTypeItems },
|
|
406
577
|
customTypes: { title: "Custom Types", items: customTypeItems },
|
|
578
|
+
allTypeStatuses: typeStatuses,
|
|
407
579
|
};
|
|
408
580
|
}
|
|
409
581
|
|
|
@@ -423,9 +595,14 @@ async function buildSlicesSection(
|
|
|
423
595
|
localSlices: SharedSlice[],
|
|
424
596
|
remoteSlices: SharedSlice[],
|
|
425
597
|
info: FrameworkInfo,
|
|
426
|
-
): Promise<
|
|
598
|
+
): Promise<{
|
|
599
|
+
section: StatusSection;
|
|
600
|
+
statuses: TypeWithStatus[];
|
|
601
|
+
missingComponents: string[];
|
|
602
|
+
}> {
|
|
427
603
|
const sliceStatuses = computeTypeStatus(localSlices, remoteSlices);
|
|
428
604
|
const items: StatusItem[] = [];
|
|
605
|
+
const missingComponents: string[] = [];
|
|
429
606
|
|
|
430
607
|
const slicesDir = getSlicesDirectory(info);
|
|
431
608
|
const extensions = getSliceComponentExtensions(info.framework);
|
|
@@ -446,6 +623,7 @@ async function buildSlicesSection(
|
|
|
446
623
|
label: slice.label,
|
|
447
624
|
hint: "missing component",
|
|
448
625
|
});
|
|
626
|
+
missingComponents.push(slice.label);
|
|
449
627
|
} else {
|
|
450
628
|
items.push({
|
|
451
629
|
done: false,
|
|
@@ -455,7 +633,11 @@ async function buildSlicesSection(
|
|
|
455
633
|
}
|
|
456
634
|
}
|
|
457
635
|
|
|
458
|
-
return {
|
|
636
|
+
return {
|
|
637
|
+
section: { title: "Slices", items },
|
|
638
|
+
statuses: sliceStatuses,
|
|
639
|
+
missingComponents,
|
|
640
|
+
};
|
|
459
641
|
}
|
|
460
642
|
|
|
461
643
|
async function checkSliceComponent(
|