@angeloashmore/prismic-cli-poc 0.0.0-pr.8.b80fefa → 0.0.0-pr.9.5366ece
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 +302 -168
- package/package.json +1 -1
- package/src/custom-type-add-field-boolean.ts +49 -12
- package/src/custom-type-add-field-color.ts +46 -12
- package/src/custom-type-add-field-date.ts +46 -12
- package/src/custom-type-add-field-embed.ts +46 -12
- package/src/custom-type-add-field-geo-point.ts +46 -12
- package/src/custom-type-add-field-group.ts +179 -0
- package/src/custom-type-add-field-image.ts +46 -12
- package/src/custom-type-add-field-key-text.ts +46 -12
- package/src/custom-type-add-field-link.ts +46 -12
- package/src/custom-type-add-field-number.ts +46 -12
- package/src/custom-type-add-field-rich-text.ts +46 -12
- package/src/custom-type-add-field-select.ts +47 -21
- package/src/custom-type-add-field-timestamp.ts +46 -12
- package/src/custom-type-add-field-uid.ts +17 -0
- package/src/custom-type-add-field.ts +5 -0
- package/src/index.ts +5 -0
- package/src/lib/field-path.ts +81 -0
- package/src/page-type-add-field-boolean.ts +66 -13
- package/src/page-type-add-field-color.ts +66 -13
- package/src/page-type-add-field-date.ts +66 -13
- package/src/page-type-add-field-embed.ts +66 -13
- package/src/page-type-add-field-geo-point.ts +66 -13
- package/src/page-type-add-field-group.ts +198 -0
- package/src/page-type-add-field-image.ts +66 -13
- package/src/page-type-add-field-key-text.ts +66 -13
- package/src/page-type-add-field-link.ts +66 -13
- package/src/page-type-add-field-number.ts +66 -13
- package/src/page-type-add-field-rich-text.ts +66 -13
- package/src/page-type-add-field-select.ts +67 -22
- package/src/page-type-add-field-timestamp.ts +66 -13
- package/src/page-type-add-field-uid.ts +37 -1
- package/src/page-type-add-field.ts +5 -0
- package/src/page-type-create.ts +25 -0
- package/src/repo-create.ts +59 -0
- package/src/skill-install.ts +177 -0
- package/src/skill-uninstall.ts +85 -0
- package/src/skill.ts +50 -0
- package/src/slice-add-field-boolean.ts +90 -16
- package/src/slice-add-field-color.ts +90 -16
- package/src/slice-add-field-date.ts +90 -16
- package/src/slice-add-field-embed.ts +90 -16
- package/src/slice-add-field-geo-point.ts +90 -16
- package/src/slice-add-field-group.ts +191 -0
- package/src/slice-add-field-image.ts +90 -16
- package/src/slice-add-field-key-text.ts +90 -16
- package/src/slice-add-field-link.ts +90 -16
- package/src/slice-add-field-number.ts +90 -16
- package/src/slice-add-field-rich-text.ts +90 -16
- package/src/slice-add-field-select.ts +91 -25
- package/src/slice-add-field-timestamp.ts +90 -16
- package/src/slice-add-field.ts +5 -0
- package/src/slice-create.ts +66 -5
- package/src/slice-set-screenshot.ts +235 -0
- package/src/slice-view.ts +3 -0
- package/src/slice.ts +5 -0
- package/src/status.ts +164 -124
|
@@ -6,6 +6,7 @@ import * as v from "valibot";
|
|
|
6
6
|
|
|
7
7
|
import { buildTypes } from "./codegen-types";
|
|
8
8
|
import { findUpward } from "./lib/file";
|
|
9
|
+
import { parseFieldPath, validateNestedFieldPath } from "./lib/field-path";
|
|
9
10
|
import { stringify } from "./lib/json";
|
|
10
11
|
import { humanReadable } from "./lib/string";
|
|
11
12
|
|
|
@@ -76,6 +77,22 @@ export async function customTypeAddFieldUid(): Promise<void> {
|
|
|
76
77
|
return;
|
|
77
78
|
}
|
|
78
79
|
|
|
80
|
+
// Parse and validate field path
|
|
81
|
+
const fieldPath = parseFieldPath(fieldId);
|
|
82
|
+
const pathValidation = validateNestedFieldPath(fieldPath);
|
|
83
|
+
if (!pathValidation.ok) {
|
|
84
|
+
console.error(pathValidation.error);
|
|
85
|
+
process.exitCode = 1;
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// UID fields cannot be nested in groups
|
|
90
|
+
if (fieldPath.type === "nested") {
|
|
91
|
+
console.error("UID fields cannot be nested inside groups");
|
|
92
|
+
process.exitCode = 1;
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
79
96
|
// Find the custom type file
|
|
80
97
|
const projectRoot = await findUpward("package.json");
|
|
81
98
|
if (!projectRoot) {
|
|
@@ -5,6 +5,7 @@ import { customTypeAddFieldColor } from "./custom-type-add-field-color";
|
|
|
5
5
|
import { customTypeAddFieldDate } from "./custom-type-add-field-date";
|
|
6
6
|
import { customTypeAddFieldEmbed } from "./custom-type-add-field-embed";
|
|
7
7
|
import { customTypeAddFieldGeoPoint } from "./custom-type-add-field-geo-point";
|
|
8
|
+
import { customTypeAddFieldGroup } from "./custom-type-add-field-group";
|
|
8
9
|
import { customTypeAddFieldImage } from "./custom-type-add-field-image";
|
|
9
10
|
import { customTypeAddFieldKeyText } from "./custom-type-add-field-key-text";
|
|
10
11
|
import { customTypeAddFieldLink } from "./custom-type-add-field-link";
|
|
@@ -26,6 +27,7 @@ FIELD TYPES
|
|
|
26
27
|
date Date picker
|
|
27
28
|
embed Embed (oEmbed)
|
|
28
29
|
geo-point Geographic coordinates
|
|
30
|
+
group Repeatable group of fields
|
|
29
31
|
image Image
|
|
30
32
|
key-text Single-line text
|
|
31
33
|
link Any link type
|
|
@@ -76,6 +78,9 @@ export async function customTypeAddField(): Promise<void> {
|
|
|
76
78
|
case "geo-point":
|
|
77
79
|
await customTypeAddFieldGeoPoint();
|
|
78
80
|
break;
|
|
81
|
+
case "group":
|
|
82
|
+
await customTypeAddFieldGroup();
|
|
83
|
+
break;
|
|
79
84
|
case "image":
|
|
80
85
|
await customTypeAddFieldImage();
|
|
81
86
|
break;
|
package/src/index.ts
CHANGED
|
@@ -16,6 +16,7 @@ import { pull } from "./pull";
|
|
|
16
16
|
import { push } from "./push";
|
|
17
17
|
import { repo } from "./repo";
|
|
18
18
|
import { slice } from "./slice";
|
|
19
|
+
import { skill } from "./skill";
|
|
19
20
|
import { status } from "./status";
|
|
20
21
|
import { token } from "./token";
|
|
21
22
|
import { webhook } from "./webhook";
|
|
@@ -42,6 +43,7 @@ COMMANDS
|
|
|
42
43
|
push Push types and slices to Prismic
|
|
43
44
|
codegen Generate code from Prismic models
|
|
44
45
|
docs Fetch documentation from Prismic
|
|
46
|
+
skill Manage Prismic AI skills
|
|
45
47
|
preview Manage preview configurations
|
|
46
48
|
token Manage API tokens in a repository
|
|
47
49
|
webhook Manage webhooks in a repository
|
|
@@ -112,6 +114,9 @@ if (version) {
|
|
|
112
114
|
case "docs":
|
|
113
115
|
await docs();
|
|
114
116
|
break;
|
|
117
|
+
case "skill":
|
|
118
|
+
await skill();
|
|
119
|
+
break;
|
|
115
120
|
case "preview":
|
|
116
121
|
await preview();
|
|
117
122
|
break;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
export type FieldPath =
|
|
2
|
+
| { type: "top-level"; fieldId: string }
|
|
3
|
+
| { type: "nested"; groupId: string; nestedFieldId: string };
|
|
4
|
+
|
|
5
|
+
export function parseFieldPath(fieldId: string): FieldPath {
|
|
6
|
+
const parts = fieldId.split(".");
|
|
7
|
+
|
|
8
|
+
if (parts.length === 1) {
|
|
9
|
+
return { type: "top-level", fieldId };
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (parts.length === 2) {
|
|
13
|
+
return { type: "nested", groupId: parts[0], nestedFieldId: parts[1] };
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// More than 2 parts means nested groups which aren't supported
|
|
17
|
+
return { type: "nested", groupId: parts[0], nestedFieldId: parts.slice(1).join(".") };
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type GroupFieldResult =
|
|
21
|
+
| { ok: true; group: { config: { fields: Record<string, unknown> } } }
|
|
22
|
+
| { ok: false; error: string };
|
|
23
|
+
|
|
24
|
+
export function isGroupField(field: unknown): field is { type: "Group"; config: { fields: Record<string, unknown> } } {
|
|
25
|
+
return (
|
|
26
|
+
typeof field === "object" &&
|
|
27
|
+
field !== null &&
|
|
28
|
+
"type" in field &&
|
|
29
|
+
field.type === "Group" &&
|
|
30
|
+
"config" in field &&
|
|
31
|
+
typeof field.config === "object" &&
|
|
32
|
+
field.config !== null &&
|
|
33
|
+
"fields" in field.config
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function findGroupInTab(
|
|
38
|
+
tabFields: Record<string, unknown>,
|
|
39
|
+
groupId: string,
|
|
40
|
+
tabName: string,
|
|
41
|
+
): GroupFieldResult {
|
|
42
|
+
const field = tabFields[groupId];
|
|
43
|
+
|
|
44
|
+
if (!field) {
|
|
45
|
+
return { ok: false, error: `Group "${groupId}" not found in tab "${tabName}"` };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (!isGroupField(field)) {
|
|
49
|
+
return { ok: false, error: `Field "${groupId}" is not a group` };
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return { ok: true, group: field };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function findGroupInVariation(
|
|
56
|
+
primary: Record<string, unknown>,
|
|
57
|
+
groupId: string,
|
|
58
|
+
variationId: string,
|
|
59
|
+
): GroupFieldResult {
|
|
60
|
+
const field = primary[groupId];
|
|
61
|
+
|
|
62
|
+
if (!field) {
|
|
63
|
+
return { ok: false, error: `Group "${groupId}" not found in variation "${variationId}"` };
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
if (!isGroupField(field)) {
|
|
67
|
+
return { ok: false, error: `Field "${groupId}" is not a group` };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return { ok: true, group: field };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function validateNestedFieldPath(fieldPath: FieldPath): { ok: true } | { ok: false; error: string } {
|
|
74
|
+
if (fieldPath.type === "nested" && fieldPath.nestedFieldId.includes(".")) {
|
|
75
|
+
return {
|
|
76
|
+
ok: false,
|
|
77
|
+
error: `Nested groups not supported. Use: group.field`,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
return { ok: true };
|
|
81
|
+
}
|
|
@@ -6,6 +6,8 @@ import * as v from "valibot";
|
|
|
6
6
|
|
|
7
7
|
import { buildTypes } from "./codegen-types";
|
|
8
8
|
import { findUpward } from "./lib/file";
|
|
9
|
+
import { findGroupInTab, isGroupField, parseFieldPath, validateNestedFieldPath } from "./lib/field-path";
|
|
10
|
+
import { type Framework, detectFrameworkInfo } from "./lib/framework";
|
|
9
11
|
import { stringify } from "./lib/json";
|
|
10
12
|
import { humanReadable } from "./lib/string";
|
|
11
13
|
|
|
@@ -43,6 +45,17 @@ const CustomTypeSchema = v.object({
|
|
|
43
45
|
json: v.record(v.string(), v.record(v.string(), v.unknown())),
|
|
44
46
|
});
|
|
45
47
|
|
|
48
|
+
function getDocsPath(framework: Framework): string {
|
|
49
|
+
switch (framework) {
|
|
50
|
+
case "next":
|
|
51
|
+
return "nextjs/with-cli";
|
|
52
|
+
case "nuxt":
|
|
53
|
+
return "nuxt/with-cli";
|
|
54
|
+
case "sveltekit":
|
|
55
|
+
return "sveltekit/with-cli";
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
46
59
|
export async function pageTypeAddFieldBoolean(): Promise<void> {
|
|
47
60
|
const {
|
|
48
61
|
values: {
|
|
@@ -88,6 +101,15 @@ export async function pageTypeAddFieldBoolean(): Promise<void> {
|
|
|
88
101
|
return;
|
|
89
102
|
}
|
|
90
103
|
|
|
104
|
+
// Parse and validate field path
|
|
105
|
+
const fieldPath = parseFieldPath(fieldId);
|
|
106
|
+
const pathValidation = validateNestedFieldPath(fieldPath);
|
|
107
|
+
if (!pathValidation.ok) {
|
|
108
|
+
console.error(pathValidation.error);
|
|
109
|
+
process.exitCode = 1;
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
91
113
|
// Find the page type file
|
|
92
114
|
const projectRoot = await findUpward("package.json");
|
|
93
115
|
if (!projectRoot) {
|
|
@@ -134,20 +156,11 @@ export async function pageTypeAddFieldBoolean(): Promise<void> {
|
|
|
134
156
|
model.json[targetTab] = {};
|
|
135
157
|
}
|
|
136
158
|
|
|
137
|
-
// Check if field already exists in any tab
|
|
138
|
-
for (const [tabName, tabFields] of Object.entries(model.json)) {
|
|
139
|
-
if (tabFields[fieldId]) {
|
|
140
|
-
console.error(`Field "${fieldId}" already exists in tab "${tabName}"`);
|
|
141
|
-
process.exitCode = 1;
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
159
|
// Build field definition
|
|
147
160
|
const fieldDefinition: BooleanField = {
|
|
148
161
|
type: "Boolean",
|
|
149
162
|
config: {
|
|
150
|
-
label: label ?? humanReadable(fieldId),
|
|
163
|
+
label: label ?? humanReadable(fieldPath.type === "nested" ? fieldPath.nestedFieldId : fieldId),
|
|
151
164
|
...(defaultValue && { default_value: true }),
|
|
152
165
|
...(trueLabel && { placeholder_true: trueLabel }),
|
|
153
166
|
...(falseLabel && { placeholder_false: falseLabel }),
|
|
@@ -155,7 +168,36 @@ export async function pageTypeAddFieldBoolean(): Promise<void> {
|
|
|
155
168
|
};
|
|
156
169
|
|
|
157
170
|
// Add field to model
|
|
158
|
-
|
|
171
|
+
if (fieldPath.type === "nested") {
|
|
172
|
+
const groupResult = findGroupInTab(model.json[targetTab], fieldPath.groupId, targetTab);
|
|
173
|
+
if (!groupResult.ok) {
|
|
174
|
+
console.error(groupResult.error);
|
|
175
|
+
process.exitCode = 1;
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (groupResult.group.config.fields[fieldPath.nestedFieldId]) {
|
|
179
|
+
console.error(`Field "${fieldPath.nestedFieldId}" already exists in group "${fieldPath.groupId}"`);
|
|
180
|
+
process.exitCode = 1;
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
groupResult.group.config.fields[fieldPath.nestedFieldId] = fieldDefinition;
|
|
184
|
+
} else {
|
|
185
|
+
for (const [tabName, tabFields] of Object.entries(model.json)) {
|
|
186
|
+
if (tabFields[fieldId]) {
|
|
187
|
+
console.error(`Field "${fieldId}" already exists in tab "${tabName}"`);
|
|
188
|
+
process.exitCode = 1;
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
for (const [groupFieldId, groupField] of Object.entries(tabFields)) {
|
|
192
|
+
if (isGroupField(groupField) && groupField.config.fields[fieldId]) {
|
|
193
|
+
console.error(`Field "${fieldId}" already exists in group "${groupFieldId}" in tab "${tabName}"`);
|
|
194
|
+
process.exitCode = 1;
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
model.json[targetTab][fieldId] = fieldDefinition;
|
|
200
|
+
}
|
|
159
201
|
|
|
160
202
|
// Write updated model
|
|
161
203
|
try {
|
|
@@ -170,7 +212,11 @@ export async function pageTypeAddFieldBoolean(): Promise<void> {
|
|
|
170
212
|
return;
|
|
171
213
|
}
|
|
172
214
|
|
|
173
|
-
|
|
215
|
+
if (fieldPath.type === "nested") {
|
|
216
|
+
console.info(`Added field "${fieldPath.nestedFieldId}" (Boolean) to group "${fieldPath.groupId}" in ${typeId}`);
|
|
217
|
+
} else {
|
|
218
|
+
console.info(`Added field "${fieldId}" (Boolean) to "${targetTab}" tab in ${typeId}`);
|
|
219
|
+
}
|
|
174
220
|
|
|
175
221
|
try {
|
|
176
222
|
await buildTypes({ output: types });
|
|
@@ -181,5 +227,12 @@ export async function pageTypeAddFieldBoolean(): Promise<void> {
|
|
|
181
227
|
|
|
182
228
|
console.info();
|
|
183
229
|
console.info("Next: Add more fields with `prismic page-type add-field`");
|
|
184
|
-
|
|
230
|
+
|
|
231
|
+
const frameworkInfo = await detectFrameworkInfo();
|
|
232
|
+
if (frameworkInfo?.framework) {
|
|
233
|
+
const docsPath = getDocsPath(frameworkInfo.framework);
|
|
234
|
+
console.info(
|
|
235
|
+
` Run \`prismic docs ${docsPath}#write-page-components\` to learn how to implement a page file`,
|
|
236
|
+
);
|
|
237
|
+
}
|
|
185
238
|
}
|
|
@@ -6,6 +6,8 @@ import * as v from "valibot";
|
|
|
6
6
|
|
|
7
7
|
import { buildTypes } from "./codegen-types";
|
|
8
8
|
import { findUpward } from "./lib/file";
|
|
9
|
+
import { findGroupInTab, isGroupField, parseFieldPath, validateNestedFieldPath } from "./lib/field-path";
|
|
10
|
+
import { type Framework, detectFrameworkInfo } from "./lib/framework";
|
|
9
11
|
import { stringify } from "./lib/json";
|
|
10
12
|
import { humanReadable } from "./lib/string";
|
|
11
13
|
|
|
@@ -41,6 +43,17 @@ const CustomTypeSchema = v.object({
|
|
|
41
43
|
json: v.record(v.string(), v.record(v.string(), v.unknown())),
|
|
42
44
|
});
|
|
43
45
|
|
|
46
|
+
function getDocsPath(framework: Framework): string {
|
|
47
|
+
switch (framework) {
|
|
48
|
+
case "next":
|
|
49
|
+
return "nextjs/with-cli";
|
|
50
|
+
case "nuxt":
|
|
51
|
+
return "nuxt/with-cli";
|
|
52
|
+
case "sveltekit":
|
|
53
|
+
return "sveltekit/with-cli";
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
44
57
|
export async function pageTypeAddFieldColor(): Promise<void> {
|
|
45
58
|
const {
|
|
46
59
|
values: { help, tab, label, placeholder, types },
|
|
@@ -76,6 +89,15 @@ export async function pageTypeAddFieldColor(): Promise<void> {
|
|
|
76
89
|
return;
|
|
77
90
|
}
|
|
78
91
|
|
|
92
|
+
// Parse and validate field path
|
|
93
|
+
const fieldPath = parseFieldPath(fieldId);
|
|
94
|
+
const pathValidation = validateNestedFieldPath(fieldPath);
|
|
95
|
+
if (!pathValidation.ok) {
|
|
96
|
+
console.error(pathValidation.error);
|
|
97
|
+
process.exitCode = 1;
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
79
101
|
// Find the page type file
|
|
80
102
|
const projectRoot = await findUpward("package.json");
|
|
81
103
|
if (!projectRoot) {
|
|
@@ -122,26 +144,46 @@ export async function pageTypeAddFieldColor(): Promise<void> {
|
|
|
122
144
|
model.json[targetTab] = {};
|
|
123
145
|
}
|
|
124
146
|
|
|
125
|
-
// Check if field already exists in any tab
|
|
126
|
-
for (const [tabName, tabFields] of Object.entries(model.json)) {
|
|
127
|
-
if (tabFields[fieldId]) {
|
|
128
|
-
console.error(`Field "${fieldId}" already exists in tab "${tabName}"`);
|
|
129
|
-
process.exitCode = 1;
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
147
|
// Build field definition
|
|
135
148
|
const fieldDefinition: Color = {
|
|
136
149
|
type: "Color",
|
|
137
150
|
config: {
|
|
138
|
-
label: label ?? humanReadable(fieldId),
|
|
151
|
+
label: label ?? humanReadable(fieldPath.type === "nested" ? fieldPath.nestedFieldId : fieldId),
|
|
139
152
|
...(placeholder && { placeholder }),
|
|
140
153
|
},
|
|
141
154
|
};
|
|
142
155
|
|
|
143
156
|
// Add field to model
|
|
144
|
-
|
|
157
|
+
if (fieldPath.type === "nested") {
|
|
158
|
+
const groupResult = findGroupInTab(model.json[targetTab], fieldPath.groupId, targetTab);
|
|
159
|
+
if (!groupResult.ok) {
|
|
160
|
+
console.error(groupResult.error);
|
|
161
|
+
process.exitCode = 1;
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
if (groupResult.group.config.fields[fieldPath.nestedFieldId]) {
|
|
165
|
+
console.error(`Field "${fieldPath.nestedFieldId}" already exists in group "${fieldPath.groupId}"`);
|
|
166
|
+
process.exitCode = 1;
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
groupResult.group.config.fields[fieldPath.nestedFieldId] = fieldDefinition;
|
|
170
|
+
} else {
|
|
171
|
+
for (const [tabName, tabFields] of Object.entries(model.json)) {
|
|
172
|
+
if (tabFields[fieldId]) {
|
|
173
|
+
console.error(`Field "${fieldId}" already exists in tab "${tabName}"`);
|
|
174
|
+
process.exitCode = 1;
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
for (const [groupFieldId, groupField] of Object.entries(tabFields)) {
|
|
178
|
+
if (isGroupField(groupField) && groupField.config.fields[fieldId]) {
|
|
179
|
+
console.error(`Field "${fieldId}" already exists in group "${groupFieldId}" in tab "${tabName}"`);
|
|
180
|
+
process.exitCode = 1;
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
model.json[targetTab][fieldId] = fieldDefinition;
|
|
186
|
+
}
|
|
145
187
|
|
|
146
188
|
// Write updated model
|
|
147
189
|
try {
|
|
@@ -156,7 +198,11 @@ export async function pageTypeAddFieldColor(): Promise<void> {
|
|
|
156
198
|
return;
|
|
157
199
|
}
|
|
158
200
|
|
|
159
|
-
|
|
201
|
+
if (fieldPath.type === "nested") {
|
|
202
|
+
console.info(`Added field "${fieldPath.nestedFieldId}" (Color) to group "${fieldPath.groupId}" in ${typeId}`);
|
|
203
|
+
} else {
|
|
204
|
+
console.info(`Added field "${fieldId}" (Color) to "${targetTab}" tab in ${typeId}`);
|
|
205
|
+
}
|
|
160
206
|
|
|
161
207
|
try {
|
|
162
208
|
await buildTypes({ output: types });
|
|
@@ -167,5 +213,12 @@ export async function pageTypeAddFieldColor(): Promise<void> {
|
|
|
167
213
|
|
|
168
214
|
console.info();
|
|
169
215
|
console.info("Next: Add more fields with `prismic page-type add-field`");
|
|
170
|
-
|
|
216
|
+
|
|
217
|
+
const frameworkInfo = await detectFrameworkInfo();
|
|
218
|
+
if (frameworkInfo?.framework) {
|
|
219
|
+
const docsPath = getDocsPath(frameworkInfo.framework);
|
|
220
|
+
console.info(
|
|
221
|
+
` Run \`prismic docs ${docsPath}#write-page-components\` to learn how to implement a page file`,
|
|
222
|
+
);
|
|
223
|
+
}
|
|
171
224
|
}
|
|
@@ -6,6 +6,8 @@ import * as v from "valibot";
|
|
|
6
6
|
|
|
7
7
|
import { buildTypes } from "./codegen-types";
|
|
8
8
|
import { findUpward } from "./lib/file";
|
|
9
|
+
import { findGroupInTab, isGroupField, parseFieldPath, validateNestedFieldPath } from "./lib/field-path";
|
|
10
|
+
import { type Framework, detectFrameworkInfo } from "./lib/framework";
|
|
9
11
|
import { stringify } from "./lib/json";
|
|
10
12
|
import { humanReadable } from "./lib/string";
|
|
11
13
|
|
|
@@ -42,6 +44,17 @@ const CustomTypeSchema = v.object({
|
|
|
42
44
|
json: v.record(v.string(), v.record(v.string(), v.unknown())),
|
|
43
45
|
});
|
|
44
46
|
|
|
47
|
+
function getDocsPath(framework: Framework): string {
|
|
48
|
+
switch (framework) {
|
|
49
|
+
case "next":
|
|
50
|
+
return "nextjs/with-cli";
|
|
51
|
+
case "nuxt":
|
|
52
|
+
return "nuxt/with-cli";
|
|
53
|
+
case "sveltekit":
|
|
54
|
+
return "sveltekit/with-cli";
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
45
58
|
export async function pageTypeAddFieldDate(): Promise<void> {
|
|
46
59
|
const {
|
|
47
60
|
values: { help, tab, label, placeholder, default: defaultValue, types },
|
|
@@ -78,6 +91,15 @@ export async function pageTypeAddFieldDate(): Promise<void> {
|
|
|
78
91
|
return;
|
|
79
92
|
}
|
|
80
93
|
|
|
94
|
+
// Parse and validate field path
|
|
95
|
+
const fieldPath = parseFieldPath(fieldId);
|
|
96
|
+
const pathValidation = validateNestedFieldPath(fieldPath);
|
|
97
|
+
if (!pathValidation.ok) {
|
|
98
|
+
console.error(pathValidation.error);
|
|
99
|
+
process.exitCode = 1;
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
81
103
|
// Find the page type file
|
|
82
104
|
const projectRoot = await findUpward("package.json");
|
|
83
105
|
if (!projectRoot) {
|
|
@@ -124,27 +146,47 @@ export async function pageTypeAddFieldDate(): Promise<void> {
|
|
|
124
146
|
model.json[targetTab] = {};
|
|
125
147
|
}
|
|
126
148
|
|
|
127
|
-
// Check if field already exists in any tab
|
|
128
|
-
for (const [tabName, tabFields] of Object.entries(model.json)) {
|
|
129
|
-
if (tabFields[fieldId]) {
|
|
130
|
-
console.error(`Field "${fieldId}" already exists in tab "${tabName}"`);
|
|
131
|
-
process.exitCode = 1;
|
|
132
|
-
return;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
149
|
// Build field definition
|
|
137
150
|
const fieldDefinition: DateField = {
|
|
138
151
|
type: "Date",
|
|
139
152
|
config: {
|
|
140
|
-
label: label ?? humanReadable(fieldId),
|
|
153
|
+
label: label ?? humanReadable(fieldPath.type === "nested" ? fieldPath.nestedFieldId : fieldId),
|
|
141
154
|
...(placeholder && { placeholder }),
|
|
142
155
|
...(defaultValue && { default: defaultValue }),
|
|
143
156
|
},
|
|
144
157
|
};
|
|
145
158
|
|
|
146
159
|
// Add field to model
|
|
147
|
-
|
|
160
|
+
if (fieldPath.type === "nested") {
|
|
161
|
+
const groupResult = findGroupInTab(model.json[targetTab], fieldPath.groupId, targetTab);
|
|
162
|
+
if (!groupResult.ok) {
|
|
163
|
+
console.error(groupResult.error);
|
|
164
|
+
process.exitCode = 1;
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if (groupResult.group.config.fields[fieldPath.nestedFieldId]) {
|
|
168
|
+
console.error(`Field "${fieldPath.nestedFieldId}" already exists in group "${fieldPath.groupId}"`);
|
|
169
|
+
process.exitCode = 1;
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
groupResult.group.config.fields[fieldPath.nestedFieldId] = fieldDefinition;
|
|
173
|
+
} else {
|
|
174
|
+
for (const [tabName, tabFields] of Object.entries(model.json)) {
|
|
175
|
+
if (tabFields[fieldId]) {
|
|
176
|
+
console.error(`Field "${fieldId}" already exists in tab "${tabName}"`);
|
|
177
|
+
process.exitCode = 1;
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
for (const [groupFieldId, groupField] of Object.entries(tabFields)) {
|
|
181
|
+
if (isGroupField(groupField) && groupField.config.fields[fieldId]) {
|
|
182
|
+
console.error(`Field "${fieldId}" already exists in group "${groupFieldId}" in tab "${tabName}"`);
|
|
183
|
+
process.exitCode = 1;
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
model.json[targetTab][fieldId] = fieldDefinition;
|
|
189
|
+
}
|
|
148
190
|
|
|
149
191
|
// Write updated model
|
|
150
192
|
try {
|
|
@@ -159,7 +201,11 @@ export async function pageTypeAddFieldDate(): Promise<void> {
|
|
|
159
201
|
return;
|
|
160
202
|
}
|
|
161
203
|
|
|
162
|
-
|
|
204
|
+
if (fieldPath.type === "nested") {
|
|
205
|
+
console.info(`Added field "${fieldPath.nestedFieldId}" (Date) to group "${fieldPath.groupId}" in ${typeId}`);
|
|
206
|
+
} else {
|
|
207
|
+
console.info(`Added field "${fieldId}" (Date) to "${targetTab}" tab in ${typeId}`);
|
|
208
|
+
}
|
|
163
209
|
|
|
164
210
|
try {
|
|
165
211
|
await buildTypes({ output: types });
|
|
@@ -170,5 +216,12 @@ export async function pageTypeAddFieldDate(): Promise<void> {
|
|
|
170
216
|
|
|
171
217
|
console.info();
|
|
172
218
|
console.info("Next: Add more fields with `prismic page-type add-field`");
|
|
173
|
-
|
|
219
|
+
|
|
220
|
+
const frameworkInfo = await detectFrameworkInfo();
|
|
221
|
+
if (frameworkInfo?.framework) {
|
|
222
|
+
const docsPath = getDocsPath(frameworkInfo.framework);
|
|
223
|
+
console.info(
|
|
224
|
+
` Run \`prismic docs ${docsPath}#write-page-components\` to learn how to implement a page file`,
|
|
225
|
+
);
|
|
226
|
+
}
|
|
174
227
|
}
|
|
@@ -6,6 +6,8 @@ import * as v from "valibot";
|
|
|
6
6
|
|
|
7
7
|
import { buildTypes } from "./codegen-types";
|
|
8
8
|
import { findUpward } from "./lib/file";
|
|
9
|
+
import { findGroupInTab, isGroupField, parseFieldPath, validateNestedFieldPath } from "./lib/field-path";
|
|
10
|
+
import { type Framework, detectFrameworkInfo } from "./lib/framework";
|
|
9
11
|
import { stringify } from "./lib/json";
|
|
10
12
|
import { humanReadable } from "./lib/string";
|
|
11
13
|
|
|
@@ -41,6 +43,17 @@ const CustomTypeSchema = v.object({
|
|
|
41
43
|
json: v.record(v.string(), v.record(v.string(), v.unknown())),
|
|
42
44
|
});
|
|
43
45
|
|
|
46
|
+
function getDocsPath(framework: Framework): string {
|
|
47
|
+
switch (framework) {
|
|
48
|
+
case "next":
|
|
49
|
+
return "nextjs/with-cli";
|
|
50
|
+
case "nuxt":
|
|
51
|
+
return "nuxt/with-cli";
|
|
52
|
+
case "sveltekit":
|
|
53
|
+
return "sveltekit/with-cli";
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
44
57
|
export async function pageTypeAddFieldEmbed(): Promise<void> {
|
|
45
58
|
const {
|
|
46
59
|
values: { help, tab, label, placeholder, types },
|
|
@@ -76,6 +89,15 @@ export async function pageTypeAddFieldEmbed(): Promise<void> {
|
|
|
76
89
|
return;
|
|
77
90
|
}
|
|
78
91
|
|
|
92
|
+
// Parse and validate field path
|
|
93
|
+
const fieldPath = parseFieldPath(fieldId);
|
|
94
|
+
const pathValidation = validateNestedFieldPath(fieldPath);
|
|
95
|
+
if (!pathValidation.ok) {
|
|
96
|
+
console.error(pathValidation.error);
|
|
97
|
+
process.exitCode = 1;
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
79
101
|
// Find the page type file
|
|
80
102
|
const projectRoot = await findUpward("package.json");
|
|
81
103
|
if (!projectRoot) {
|
|
@@ -122,26 +144,46 @@ export async function pageTypeAddFieldEmbed(): Promise<void> {
|
|
|
122
144
|
model.json[targetTab] = {};
|
|
123
145
|
}
|
|
124
146
|
|
|
125
|
-
// Check if field already exists in any tab
|
|
126
|
-
for (const [tabName, tabFields] of Object.entries(model.json)) {
|
|
127
|
-
if (tabFields[fieldId]) {
|
|
128
|
-
console.error(`Field "${fieldId}" already exists in tab "${tabName}"`);
|
|
129
|
-
process.exitCode = 1;
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
147
|
// Build field definition
|
|
135
148
|
const fieldDefinition: Embed = {
|
|
136
149
|
type: "Embed",
|
|
137
150
|
config: {
|
|
138
|
-
label: label ?? humanReadable(fieldId),
|
|
151
|
+
label: label ?? humanReadable(fieldPath.type === "nested" ? fieldPath.nestedFieldId : fieldId),
|
|
139
152
|
...(placeholder && { placeholder }),
|
|
140
153
|
},
|
|
141
154
|
};
|
|
142
155
|
|
|
143
156
|
// Add field to model
|
|
144
|
-
|
|
157
|
+
if (fieldPath.type === "nested") {
|
|
158
|
+
const groupResult = findGroupInTab(model.json[targetTab], fieldPath.groupId, targetTab);
|
|
159
|
+
if (!groupResult.ok) {
|
|
160
|
+
console.error(groupResult.error);
|
|
161
|
+
process.exitCode = 1;
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
if (groupResult.group.config.fields[fieldPath.nestedFieldId]) {
|
|
165
|
+
console.error(`Field "${fieldPath.nestedFieldId}" already exists in group "${fieldPath.groupId}"`);
|
|
166
|
+
process.exitCode = 1;
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
groupResult.group.config.fields[fieldPath.nestedFieldId] = fieldDefinition;
|
|
170
|
+
} else {
|
|
171
|
+
for (const [tabName, tabFields] of Object.entries(model.json)) {
|
|
172
|
+
if (tabFields[fieldId]) {
|
|
173
|
+
console.error(`Field "${fieldId}" already exists in tab "${tabName}"`);
|
|
174
|
+
process.exitCode = 1;
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
for (const [groupFieldId, groupField] of Object.entries(tabFields)) {
|
|
178
|
+
if (isGroupField(groupField) && groupField.config.fields[fieldId]) {
|
|
179
|
+
console.error(`Field "${fieldId}" already exists in group "${groupFieldId}" in tab "${tabName}"`);
|
|
180
|
+
process.exitCode = 1;
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
model.json[targetTab][fieldId] = fieldDefinition;
|
|
186
|
+
}
|
|
145
187
|
|
|
146
188
|
// Write updated model
|
|
147
189
|
try {
|
|
@@ -156,7 +198,11 @@ export async function pageTypeAddFieldEmbed(): Promise<void> {
|
|
|
156
198
|
return;
|
|
157
199
|
}
|
|
158
200
|
|
|
159
|
-
|
|
201
|
+
if (fieldPath.type === "nested") {
|
|
202
|
+
console.info(`Added field "${fieldPath.nestedFieldId}" (Embed) to group "${fieldPath.groupId}" in ${typeId}`);
|
|
203
|
+
} else {
|
|
204
|
+
console.info(`Added field "${fieldId}" (Embed) to "${targetTab}" tab in ${typeId}`);
|
|
205
|
+
}
|
|
160
206
|
|
|
161
207
|
try {
|
|
162
208
|
await buildTypes({ output: types });
|
|
@@ -167,5 +213,12 @@ export async function pageTypeAddFieldEmbed(): Promise<void> {
|
|
|
167
213
|
|
|
168
214
|
console.info();
|
|
169
215
|
console.info("Next: Add more fields with `prismic page-type add-field`");
|
|
170
|
-
|
|
216
|
+
|
|
217
|
+
const frameworkInfo = await detectFrameworkInfo();
|
|
218
|
+
if (frameworkInfo?.framework) {
|
|
219
|
+
const docsPath = getDocsPath(frameworkInfo.framework);
|
|
220
|
+
console.info(
|
|
221
|
+
` Run \`prismic docs ${docsPath}#write-page-components\` to learn how to implement a page file`,
|
|
222
|
+
);
|
|
223
|
+
}
|
|
171
224
|
}
|