@angeloashmore/prismic-cli-poc 0.0.0-canary.5da487c → 0.0.0-canary.63deeeb
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 +114 -95
- package/package.json +1 -1
- package/src/docs.ts +149 -0
- package/src/index.ts +5 -0
- package/src/status.ts +49 -12
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
|
@@ -66,16 +66,53 @@ type NextStep = {
|
|
|
66
66
|
message: string;
|
|
67
67
|
};
|
|
68
68
|
|
|
69
|
-
function
|
|
69
|
+
function getDocsPath(framework: Framework | undefined): string {
|
|
70
70
|
switch (framework) {
|
|
71
71
|
case "next":
|
|
72
|
-
return "
|
|
72
|
+
return "nextjs/with-cli";
|
|
73
73
|
case "nuxt":
|
|
74
|
-
return "
|
|
74
|
+
return "nuxt/with-cli";
|
|
75
75
|
case "sveltekit":
|
|
76
|
-
return "
|
|
76
|
+
return "sveltekit/with-cli";
|
|
77
77
|
default:
|
|
78
|
-
return "
|
|
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
|
|
|
@@ -86,7 +123,7 @@ function computeNextStep(
|
|
|
86
123
|
sliceStatuses: TypeWithStatus[],
|
|
87
124
|
slicesWithMissingComponents: string[],
|
|
88
125
|
): NextStep | undefined {
|
|
89
|
-
const
|
|
126
|
+
const docsPath = getDocsPath(frameworkInfo.framework);
|
|
90
127
|
|
|
91
128
|
// 1. Setup - missing dependencies
|
|
92
129
|
const setupSection = sections.find((s) => s.title === "Setup");
|
|
@@ -99,7 +136,7 @@ function computeNextStep(
|
|
|
99
136
|
// 2. Setup - missing client file
|
|
100
137
|
const missingClientFile = setupSection?.items.find((i) => !i.done && i.hint?.includes("client"));
|
|
101
138
|
if (missingClientFile) {
|
|
102
|
-
return { message: `Create a ${missingClientFile.label} file (
|
|
139
|
+
return { message: `Create a ${missingClientFile.label} file${getDocsRef(docsPath, getClientSetupAnchor(frameworkInfo.framework))}` };
|
|
103
140
|
}
|
|
104
141
|
|
|
105
142
|
// 3-7. Preview section (in order: local files, then remote config)
|
|
@@ -110,21 +147,21 @@ function computeNextStep(
|
|
|
110
147
|
(i) => i.label === "/slice-simulator route" && !i.done,
|
|
111
148
|
);
|
|
112
149
|
if (sliceSimRoute) {
|
|
113
|
-
return { message: `Create the /slice-simulator route
|
|
150
|
+
return { message: `Create the /slice-simulator route${getDocsRef(docsPath, "#set-up-live-previewing")}` };
|
|
114
151
|
}
|
|
115
152
|
|
|
116
153
|
const apiPreview = previewSection.items.find(
|
|
117
154
|
(i) => i.label === "/api/preview endpoint" && !i.done,
|
|
118
155
|
);
|
|
119
156
|
if (apiPreview) {
|
|
120
|
-
return { message: `Create the /api/preview route (
|
|
157
|
+
return { message: `Create the /api/preview route${getDocsRef(docsPath, getPreviewSetupAnchor(frameworkInfo.framework))}` };
|
|
121
158
|
}
|
|
122
159
|
|
|
123
160
|
const exitPreview = previewSection.items.find(
|
|
124
161
|
(i) => i.label === "/api/exit-preview endpoint" && !i.done,
|
|
125
162
|
);
|
|
126
163
|
if (exitPreview) {
|
|
127
|
-
return { message: `Create the /api/exit-preview route (
|
|
164
|
+
return { message: `Create the /api/exit-preview route${getDocsRef(docsPath, getPreviewSetupAnchor(frameworkInfo.framework))}` };
|
|
128
165
|
}
|
|
129
166
|
|
|
130
167
|
// Remote config
|
|
@@ -166,7 +203,7 @@ function computeNextStep(
|
|
|
166
203
|
const slicesDir = getSlicesDirectory(frameworkInfo);
|
|
167
204
|
const ext = getSliceComponentExtensions(frameworkInfo.framework)[0];
|
|
168
205
|
const path = `${slicesDir}${sliceName}/index${ext}`;
|
|
169
|
-
return { message: `Implement the ${sliceName} slice component at ${path} (
|
|
206
|
+
return { message: `Implement the ${sliceName} slice component at ${path}${getDocsRef(docsPath, getWriteComponentsAnchor(frameworkInfo.framework))}` };
|
|
170
207
|
}
|
|
171
208
|
|
|
172
209
|
// 11-12. Deployment (Next.js only)
|
|
@@ -176,7 +213,7 @@ function computeNextStep(
|
|
|
176
213
|
(i) => i.label === "/api/revalidate endpoint" && !i.done,
|
|
177
214
|
);
|
|
178
215
|
if (revalidateEndpoint) {
|
|
179
|
-
return { message: `Create the /api/revalidate route for ISR
|
|
216
|
+
return { message: `Create the /api/revalidate route for ISR${getDocsRef(docsPath, "#handle-content-changes")}` };
|
|
180
217
|
}
|
|
181
218
|
|
|
182
219
|
const webhook = deploymentSection.items.find(
|