@angeloashmore/prismic-cli-poc 0.0.0-canary.fe51fbb → 0.0.0-pr.10.032f7ef

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 (54) hide show
  1. package/dist/index.mjs +229 -136
  2. package/package.json +1 -1
  3. package/src/custom-type-add-field-boolean.ts +49 -12
  4. package/src/custom-type-add-field-color.ts +46 -12
  5. package/src/custom-type-add-field-date.ts +46 -12
  6. package/src/custom-type-add-field-embed.ts +46 -12
  7. package/src/custom-type-add-field-geo-point.ts +46 -12
  8. package/src/custom-type-add-field-group.ts +179 -0
  9. package/src/custom-type-add-field-image.ts +46 -12
  10. package/src/custom-type-add-field-key-text.ts +46 -12
  11. package/src/custom-type-add-field-link.ts +46 -12
  12. package/src/custom-type-add-field-number.ts +46 -12
  13. package/src/custom-type-add-field-rich-text.ts +46 -12
  14. package/src/custom-type-add-field-select.ts +46 -12
  15. package/src/custom-type-add-field-timestamp.ts +46 -12
  16. package/src/custom-type-add-field-uid.ts +17 -0
  17. package/src/custom-type-add-field.ts +5 -0
  18. package/src/docs-fetch.ts +146 -0
  19. package/src/docs-list.ts +131 -0
  20. package/src/docs.ts +26 -121
  21. package/src/index.ts +1 -1
  22. package/src/lib/field-path.ts +81 -0
  23. package/src/page-type-add-field-boolean.ts +47 -13
  24. package/src/page-type-add-field-color.ts +47 -13
  25. package/src/page-type-add-field-date.ts +47 -13
  26. package/src/page-type-add-field-embed.ts +47 -13
  27. package/src/page-type-add-field-geo-point.ts +47 -13
  28. package/src/page-type-add-field-group.ts +198 -0
  29. package/src/page-type-add-field-image.ts +47 -13
  30. package/src/page-type-add-field-key-text.ts +47 -13
  31. package/src/page-type-add-field-link.ts +47 -13
  32. package/src/page-type-add-field-number.ts +47 -13
  33. package/src/page-type-add-field-rich-text.ts +47 -13
  34. package/src/page-type-add-field-select.ts +47 -13
  35. package/src/page-type-add-field-timestamp.ts +47 -13
  36. package/src/page-type-add-field-uid.ts +18 -1
  37. package/src/page-type-add-field.ts +5 -0
  38. package/src/page-type-create.ts +1 -1
  39. package/src/repo-create.ts +28 -1
  40. package/src/slice-add-field-boolean.ts +59 -16
  41. package/src/slice-add-field-color.ts +59 -16
  42. package/src/slice-add-field-date.ts +59 -16
  43. package/src/slice-add-field-embed.ts +59 -16
  44. package/src/slice-add-field-geo-point.ts +59 -16
  45. package/src/slice-add-field-group.ts +191 -0
  46. package/src/slice-add-field-image.ts +59 -16
  47. package/src/slice-add-field-key-text.ts +59 -16
  48. package/src/slice-add-field-link.ts +59 -16
  49. package/src/slice-add-field-number.ts +59 -16
  50. package/src/slice-add-field-rich-text.ts +59 -16
  51. package/src/slice-add-field-select.ts +59 -16
  52. package/src/slice-add-field-timestamp.ts +59 -16
  53. package/src/slice-add-field.ts +5 -0
  54. package/src/status.ts +1 -1
@@ -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 { findGroupInTab, isGroupField, parseFieldPath, validateNestedFieldPath } from "./lib/field-path";
9
10
  import { type Framework, detectFrameworkInfo } from "./lib/framework";
10
11
  import { stringify } from "./lib/json";
11
12
  import { humanReadable } from "./lib/string";
@@ -88,6 +89,15 @@ export async function pageTypeAddFieldImage(): Promise<void> {
88
89
  return;
89
90
  }
90
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
+
91
101
  // Find the page type file
92
102
  const projectRoot = await findUpward("package.json");
93
103
  if (!projectRoot) {
@@ -134,26 +144,46 @@ export async function pageTypeAddFieldImage(): Promise<void> {
134
144
  model.json[targetTab] = {};
135
145
  }
136
146
 
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
147
  // Build field definition
147
148
  const fieldDefinition: Image = {
148
149
  type: "Image",
149
150
  config: {
150
- label: label ?? humanReadable(fieldId),
151
+ label: label ?? humanReadable(fieldPath.type === "nested" ? fieldPath.nestedFieldId : fieldId),
151
152
  ...(placeholder && { placeholder }),
152
153
  },
153
154
  };
154
155
 
155
156
  // Add field to model
156
- model.json[targetTab][fieldId] = fieldDefinition;
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
+ }
157
187
 
158
188
  // Write updated model
159
189
  try {
@@ -168,7 +198,11 @@ export async function pageTypeAddFieldImage(): Promise<void> {
168
198
  return;
169
199
  }
170
200
 
171
- console.info(`Added field "${fieldId}" (Image) to "${targetTab}" tab in ${typeId}`);
201
+ if (fieldPath.type === "nested") {
202
+ console.info(`Added field "${fieldPath.nestedFieldId}" (Image) to group "${fieldPath.groupId}" in ${typeId}`);
203
+ } else {
204
+ console.info(`Added field "${fieldId}" (Image) to "${targetTab}" tab in ${typeId}`);
205
+ }
172
206
 
173
207
  try {
174
208
  await buildTypes({ output: types });
@@ -184,7 +218,7 @@ export async function pageTypeAddFieldImage(): Promise<void> {
184
218
  if (frameworkInfo?.framework) {
185
219
  const docsPath = getDocsPath(frameworkInfo.framework);
186
220
  console.info(
187
- ` Run \`prismic docs ${docsPath}#write-page-components\` to learn how to implement a page file`,
221
+ ` Run \`prismic docs fetch ${docsPath}#write-page-components\` to learn how to implement a page file`,
188
222
  );
189
223
  }
190
224
  }
@@ -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 { findGroupInTab, isGroupField, parseFieldPath, validateNestedFieldPath } from "./lib/field-path";
9
10
  import { type Framework, detectFrameworkInfo } from "./lib/framework";
10
11
  import { stringify } from "./lib/json";
11
12
  import { humanReadable } from "./lib/string";
@@ -88,6 +89,15 @@ export async function pageTypeAddFieldKeyText(): Promise<void> {
88
89
  return;
89
90
  }
90
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
+
91
101
  // Find the page type file
92
102
  const projectRoot = await findUpward("package.json");
93
103
  if (!projectRoot) {
@@ -134,26 +144,46 @@ export async function pageTypeAddFieldKeyText(): Promise<void> {
134
144
  model.json[targetTab] = {};
135
145
  }
136
146
 
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
147
  // Build field definition
147
148
  const fieldDefinition: Text = {
148
149
  type: "Text",
149
150
  config: {
150
- label: label ?? humanReadable(fieldId),
151
+ label: label ?? humanReadable(fieldPath.type === "nested" ? fieldPath.nestedFieldId : fieldId),
151
152
  ...(placeholder && { placeholder }),
152
153
  },
153
154
  };
154
155
 
155
156
  // Add field to model
156
- model.json[targetTab][fieldId] = fieldDefinition;
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
+ }
157
187
 
158
188
  // Write updated model
159
189
  try {
@@ -168,7 +198,11 @@ export async function pageTypeAddFieldKeyText(): Promise<void> {
168
198
  return;
169
199
  }
170
200
 
171
- console.info(`Added field "${fieldId}" (Text) to "${targetTab}" tab in ${typeId}`);
201
+ if (fieldPath.type === "nested") {
202
+ console.info(`Added field "${fieldPath.nestedFieldId}" (Text) to group "${fieldPath.groupId}" in ${typeId}`);
203
+ } else {
204
+ console.info(`Added field "${fieldId}" (Text) to "${targetTab}" tab in ${typeId}`);
205
+ }
172
206
 
173
207
  try {
174
208
  await buildTypes({ output: types });
@@ -184,7 +218,7 @@ export async function pageTypeAddFieldKeyText(): Promise<void> {
184
218
  if (frameworkInfo?.framework) {
185
219
  const docsPath = getDocsPath(frameworkInfo.framework);
186
220
  console.info(
187
- ` Run \`prismic docs ${docsPath}#write-page-components\` to learn how to implement a page file`,
221
+ ` Run \`prismic docs fetch ${docsPath}#write-page-components\` to learn how to implement a page file`,
188
222
  );
189
223
  }
190
224
  }
@@ -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 { findGroupInTab, isGroupField, parseFieldPath, validateNestedFieldPath } from "./lib/field-path";
9
10
  import { type Framework, detectFrameworkInfo } from "./lib/framework";
10
11
  import { stringify } from "./lib/json";
11
12
  import { humanReadable } from "./lib/string";
@@ -107,6 +108,15 @@ export async function pageTypeAddFieldLink(): Promise<void> {
107
108
  return;
108
109
  }
109
110
 
111
+ // Parse and validate field path
112
+ const fieldPath = parseFieldPath(fieldId);
113
+ const pathValidation = validateNestedFieldPath(fieldPath);
114
+ if (!pathValidation.ok) {
115
+ console.error(pathValidation.error);
116
+ process.exitCode = 1;
117
+ return;
118
+ }
119
+
110
120
  // Find the page type file
111
121
  const projectRoot = await findUpward("package.json");
112
122
  if (!projectRoot) {
@@ -153,20 +163,11 @@ export async function pageTypeAddFieldLink(): Promise<void> {
153
163
  model.json[targetTab] = {};
154
164
  }
155
165
 
156
- // Check if field already exists in any tab
157
- for (const [tabName, tabFields] of Object.entries(model.json)) {
158
- if (tabFields[fieldId]) {
159
- console.error(`Field "${fieldId}" already exists in tab "${tabName}"`);
160
- process.exitCode = 1;
161
- return;
162
- }
163
- }
164
-
165
166
  // Build field definition
166
167
  const fieldDefinition: Link = {
167
168
  type: "Link",
168
169
  config: {
169
- label: label ?? humanReadable(fieldId),
170
+ label: label ?? humanReadable(fieldPath.type === "nested" ? fieldPath.nestedFieldId : fieldId),
170
171
  ...(placeholder && { placeholder }),
171
172
  ...(variation && variation.length > 0 && { variants: variation }),
172
173
  ...(allowText && { allowText: true }),
@@ -176,7 +177,36 @@ export async function pageTypeAddFieldLink(): Promise<void> {
176
177
  };
177
178
 
178
179
  // Add field to model
179
- model.json[targetTab][fieldId] = fieldDefinition;
180
+ if (fieldPath.type === "nested") {
181
+ const groupResult = findGroupInTab(model.json[targetTab], fieldPath.groupId, targetTab);
182
+ if (!groupResult.ok) {
183
+ console.error(groupResult.error);
184
+ process.exitCode = 1;
185
+ return;
186
+ }
187
+ if (groupResult.group.config.fields[fieldPath.nestedFieldId]) {
188
+ console.error(`Field "${fieldPath.nestedFieldId}" already exists in group "${fieldPath.groupId}"`);
189
+ process.exitCode = 1;
190
+ return;
191
+ }
192
+ groupResult.group.config.fields[fieldPath.nestedFieldId] = fieldDefinition;
193
+ } else {
194
+ for (const [tabName, tabFields] of Object.entries(model.json)) {
195
+ if (tabFields[fieldId]) {
196
+ console.error(`Field "${fieldId}" already exists in tab "${tabName}"`);
197
+ process.exitCode = 1;
198
+ return;
199
+ }
200
+ for (const [groupFieldId, groupField] of Object.entries(tabFields)) {
201
+ if (isGroupField(groupField) && groupField.config.fields[fieldId]) {
202
+ console.error(`Field "${fieldId}" already exists in group "${groupFieldId}" in tab "${tabName}"`);
203
+ process.exitCode = 1;
204
+ return;
205
+ }
206
+ }
207
+ }
208
+ model.json[targetTab][fieldId] = fieldDefinition;
209
+ }
180
210
 
181
211
  // Write updated model
182
212
  try {
@@ -191,7 +221,11 @@ export async function pageTypeAddFieldLink(): Promise<void> {
191
221
  return;
192
222
  }
193
223
 
194
- console.info(`Added field "${fieldId}" (Link) to "${targetTab}" tab in ${typeId}`);
224
+ if (fieldPath.type === "nested") {
225
+ console.info(`Added field "${fieldPath.nestedFieldId}" (Link) to group "${fieldPath.groupId}" in ${typeId}`);
226
+ } else {
227
+ console.info(`Added field "${fieldId}" (Link) to "${targetTab}" tab in ${typeId}`);
228
+ }
195
229
 
196
230
  try {
197
231
  await buildTypes({ output: types });
@@ -207,7 +241,7 @@ export async function pageTypeAddFieldLink(): Promise<void> {
207
241
  if (frameworkInfo?.framework) {
208
242
  const docsPath = getDocsPath(frameworkInfo.framework);
209
243
  console.info(
210
- ` Run \`prismic docs ${docsPath}#write-page-components\` to learn how to implement a page file`,
244
+ ` Run \`prismic docs fetch ${docsPath}#write-page-components\` to learn how to implement a page file`,
211
245
  );
212
246
  }
213
247
  }
@@ -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 { findGroupInTab, isGroupField, parseFieldPath, validateNestedFieldPath } from "./lib/field-path";
9
10
  import { type Framework, detectFrameworkInfo } from "./lib/framework";
10
11
  import { stringify } from "./lib/json";
11
12
  import { humanReadable } from "./lib/string";
@@ -94,6 +95,15 @@ export async function pageTypeAddFieldNumber(): Promise<void> {
94
95
  return;
95
96
  }
96
97
 
98
+ // Parse and validate field path
99
+ const fieldPath = parseFieldPath(fieldId);
100
+ const pathValidation = validateNestedFieldPath(fieldPath);
101
+ if (!pathValidation.ok) {
102
+ console.error(pathValidation.error);
103
+ process.exitCode = 1;
104
+ return;
105
+ }
106
+
97
107
  // Parse numeric values
98
108
  const minValue = min !== undefined ? Number(min) : undefined;
99
109
  const maxValue = max !== undefined ? Number(max) : undefined;
@@ -163,20 +173,11 @@ export async function pageTypeAddFieldNumber(): Promise<void> {
163
173
  model.json[targetTab] = {};
164
174
  }
165
175
 
166
- // Check if field already exists in any tab
167
- for (const [tabName, tabFields] of Object.entries(model.json)) {
168
- if (tabFields[fieldId]) {
169
- console.error(`Field "${fieldId}" already exists in tab "${tabName}"`);
170
- process.exitCode = 1;
171
- return;
172
- }
173
- }
174
-
175
176
  // Build field definition
176
177
  const fieldDefinition: NumberField = {
177
178
  type: "Number",
178
179
  config: {
179
- label: label ?? humanReadable(fieldId),
180
+ label: label ?? humanReadable(fieldPath.type === "nested" ? fieldPath.nestedFieldId : fieldId),
180
181
  ...(placeholder && { placeholder }),
181
182
  ...(minValue !== undefined && { min: minValue }),
182
183
  ...(maxValue !== undefined && { max: maxValue }),
@@ -185,7 +186,36 @@ export async function pageTypeAddFieldNumber(): Promise<void> {
185
186
  };
186
187
 
187
188
  // Add field to model
188
- model.json[targetTab][fieldId] = fieldDefinition;
189
+ if (fieldPath.type === "nested") {
190
+ const groupResult = findGroupInTab(model.json[targetTab], fieldPath.groupId, targetTab);
191
+ if (!groupResult.ok) {
192
+ console.error(groupResult.error);
193
+ process.exitCode = 1;
194
+ return;
195
+ }
196
+ if (groupResult.group.config.fields[fieldPath.nestedFieldId]) {
197
+ console.error(`Field "${fieldPath.nestedFieldId}" already exists in group "${fieldPath.groupId}"`);
198
+ process.exitCode = 1;
199
+ return;
200
+ }
201
+ groupResult.group.config.fields[fieldPath.nestedFieldId] = fieldDefinition;
202
+ } else {
203
+ for (const [tabName, tabFields] of Object.entries(model.json)) {
204
+ if (tabFields[fieldId]) {
205
+ console.error(`Field "${fieldId}" already exists in tab "${tabName}"`);
206
+ process.exitCode = 1;
207
+ return;
208
+ }
209
+ for (const [groupFieldId, groupField] of Object.entries(tabFields)) {
210
+ if (isGroupField(groupField) && groupField.config.fields[fieldId]) {
211
+ console.error(`Field "${fieldId}" already exists in group "${groupFieldId}" in tab "${tabName}"`);
212
+ process.exitCode = 1;
213
+ return;
214
+ }
215
+ }
216
+ }
217
+ model.json[targetTab][fieldId] = fieldDefinition;
218
+ }
189
219
 
190
220
  // Write updated model
191
221
  try {
@@ -200,7 +230,11 @@ export async function pageTypeAddFieldNumber(): Promise<void> {
200
230
  return;
201
231
  }
202
232
 
203
- console.info(`Added field "${fieldId}" (Number) to "${targetTab}" tab in ${typeId}`);
233
+ if (fieldPath.type === "nested") {
234
+ console.info(`Added field "${fieldPath.nestedFieldId}" (Number) to group "${fieldPath.groupId}" in ${typeId}`);
235
+ } else {
236
+ console.info(`Added field "${fieldId}" (Number) to "${targetTab}" tab in ${typeId}`);
237
+ }
204
238
 
205
239
  try {
206
240
  await buildTypes({ output: types });
@@ -216,7 +250,7 @@ export async function pageTypeAddFieldNumber(): Promise<void> {
216
250
  if (frameworkInfo?.framework) {
217
251
  const docsPath = getDocsPath(frameworkInfo.framework);
218
252
  console.info(
219
- ` Run \`prismic docs ${docsPath}#write-page-components\` to learn how to implement a page file`,
253
+ ` Run \`prismic docs fetch ${docsPath}#write-page-components\` to learn how to implement a page file`,
220
254
  );
221
255
  }
222
256
  }
@@ -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 { findGroupInTab, isGroupField, parseFieldPath, validateNestedFieldPath } from "./lib/field-path";
9
10
  import { type Framework, detectFrameworkInfo } from "./lib/framework";
10
11
  import { stringify } from "./lib/json";
11
12
  import { humanReadable } from "./lib/string";
@@ -109,6 +110,15 @@ export async function pageTypeAddFieldRichText(): Promise<void> {
109
110
  return;
110
111
  }
111
112
 
113
+ // Parse and validate field path
114
+ const fieldPath = parseFieldPath(fieldId);
115
+ const pathValidation = validateNestedFieldPath(fieldPath);
116
+ if (!pathValidation.ok) {
117
+ console.error(pathValidation.error);
118
+ process.exitCode = 1;
119
+ return;
120
+ }
121
+
112
122
  // Find the page type file
113
123
  const projectRoot = await findUpward("package.json");
114
124
  if (!projectRoot) {
@@ -155,20 +165,11 @@ export async function pageTypeAddFieldRichText(): Promise<void> {
155
165
  model.json[targetTab] = {};
156
166
  }
157
167
 
158
- // Check if field already exists in any tab
159
- for (const [tabName, tabFields] of Object.entries(model.json)) {
160
- if (tabFields[fieldId]) {
161
- console.error(`Field "${fieldId}" already exists in tab "${tabName}"`);
162
- process.exitCode = 1;
163
- return;
164
- }
165
- }
166
-
167
168
  // Build field definition
168
169
  const fieldDefinition: RichText = {
169
170
  type: "StructuredText",
170
171
  config: {
171
- label: label ?? humanReadable(fieldId),
172
+ label: label ?? humanReadable(fieldPath.type === "nested" ? fieldPath.nestedFieldId : fieldId),
172
173
  ...(placeholder && { placeholder }),
173
174
  ...(single && { single }),
174
175
  ...(multi && { multi }),
@@ -177,7 +178,36 @@ export async function pageTypeAddFieldRichText(): Promise<void> {
177
178
  };
178
179
 
179
180
  // Add field to model
180
- model.json[targetTab][fieldId] = fieldDefinition;
181
+ if (fieldPath.type === "nested") {
182
+ const groupResult = findGroupInTab(model.json[targetTab], fieldPath.groupId, targetTab);
183
+ if (!groupResult.ok) {
184
+ console.error(groupResult.error);
185
+ process.exitCode = 1;
186
+ return;
187
+ }
188
+ if (groupResult.group.config.fields[fieldPath.nestedFieldId]) {
189
+ console.error(`Field "${fieldPath.nestedFieldId}" already exists in group "${fieldPath.groupId}"`);
190
+ process.exitCode = 1;
191
+ return;
192
+ }
193
+ groupResult.group.config.fields[fieldPath.nestedFieldId] = fieldDefinition;
194
+ } else {
195
+ for (const [tabName, tabFields] of Object.entries(model.json)) {
196
+ if (tabFields[fieldId]) {
197
+ console.error(`Field "${fieldId}" already exists in tab "${tabName}"`);
198
+ process.exitCode = 1;
199
+ return;
200
+ }
201
+ for (const [groupFieldId, groupField] of Object.entries(tabFields)) {
202
+ if (isGroupField(groupField) && groupField.config.fields[fieldId]) {
203
+ console.error(`Field "${fieldId}" already exists in group "${groupFieldId}" in tab "${tabName}"`);
204
+ process.exitCode = 1;
205
+ return;
206
+ }
207
+ }
208
+ }
209
+ model.json[targetTab][fieldId] = fieldDefinition;
210
+ }
181
211
 
182
212
  // Write updated model
183
213
  try {
@@ -192,7 +222,11 @@ export async function pageTypeAddFieldRichText(): Promise<void> {
192
222
  return;
193
223
  }
194
224
 
195
- console.info(`Added field "${fieldId}" (StructuredText) to "${targetTab}" tab in ${typeId}`);
225
+ if (fieldPath.type === "nested") {
226
+ console.info(`Added field "${fieldPath.nestedFieldId}" (StructuredText) to group "${fieldPath.groupId}" in ${typeId}`);
227
+ } else {
228
+ console.info(`Added field "${fieldId}" (StructuredText) to "${targetTab}" tab in ${typeId}`);
229
+ }
196
230
 
197
231
  try {
198
232
  await buildTypes({ output: types });
@@ -208,7 +242,7 @@ export async function pageTypeAddFieldRichText(): Promise<void> {
208
242
  if (frameworkInfo?.framework) {
209
243
  const docsPath = getDocsPath(frameworkInfo.framework);
210
244
  console.info(
211
- ` Run \`prismic docs ${docsPath}#write-page-components\` to learn how to implement a page file`,
245
+ ` Run \`prismic docs fetch ${docsPath}#write-page-components\` to learn how to implement a page file`,
212
246
  );
213
247
  }
214
248
  }
@@ -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 { findGroupInTab, isGroupField, parseFieldPath, validateNestedFieldPath } from "./lib/field-path";
9
10
  import { type Framework, detectFrameworkInfo } from "./lib/framework";
10
11
  import { stringify } from "./lib/json";
11
12
  import { humanReadable } from "./lib/string";
@@ -92,6 +93,15 @@ export async function pageTypeAddFieldSelect(): Promise<void> {
92
93
  return;
93
94
  }
94
95
 
96
+ // Parse and validate field path
97
+ const fieldPath = parseFieldPath(fieldId);
98
+ const pathValidation = validateNestedFieldPath(fieldPath);
99
+ if (!pathValidation.ok) {
100
+ console.error(pathValidation.error);
101
+ process.exitCode = 1;
102
+ return;
103
+ }
104
+
95
105
  // Find the page type file
96
106
  const projectRoot = await findUpward("package.json");
97
107
  if (!projectRoot) {
@@ -138,20 +148,11 @@ export async function pageTypeAddFieldSelect(): Promise<void> {
138
148
  model.json[targetTab] = {};
139
149
  }
140
150
 
141
- // Check if field already exists in any tab
142
- for (const [tabName, tabFields] of Object.entries(model.json)) {
143
- if (tabFields[fieldId]) {
144
- console.error(`Field "${fieldId}" already exists in tab "${tabName}"`);
145
- process.exitCode = 1;
146
- return;
147
- }
148
- }
149
-
150
151
  // Build field definition
151
152
  const fieldDefinition: Select = {
152
153
  type: "Select",
153
154
  config: {
154
- label: label ?? humanReadable(fieldId),
155
+ label: label ?? humanReadable(fieldPath.type === "nested" ? fieldPath.nestedFieldId : fieldId),
155
156
  ...(placeholder && { placeholder }),
156
157
  ...(option && option.length > 0 && { options: option }),
157
158
  ...(defaultValue && { default_value: defaultValue }),
@@ -159,7 +160,36 @@ export async function pageTypeAddFieldSelect(): Promise<void> {
159
160
  };
160
161
 
161
162
  // Add field to model
162
- model.json[targetTab][fieldId] = fieldDefinition;
163
+ if (fieldPath.type === "nested") {
164
+ const groupResult = findGroupInTab(model.json[targetTab], fieldPath.groupId, targetTab);
165
+ if (!groupResult.ok) {
166
+ console.error(groupResult.error);
167
+ process.exitCode = 1;
168
+ return;
169
+ }
170
+ if (groupResult.group.config.fields[fieldPath.nestedFieldId]) {
171
+ console.error(`Field "${fieldPath.nestedFieldId}" already exists in group "${fieldPath.groupId}"`);
172
+ process.exitCode = 1;
173
+ return;
174
+ }
175
+ groupResult.group.config.fields[fieldPath.nestedFieldId] = fieldDefinition;
176
+ } else {
177
+ for (const [tabName, tabFields] of Object.entries(model.json)) {
178
+ if (tabFields[fieldId]) {
179
+ console.error(`Field "${fieldId}" already exists in tab "${tabName}"`);
180
+ process.exitCode = 1;
181
+ return;
182
+ }
183
+ for (const [groupFieldId, groupField] of Object.entries(tabFields)) {
184
+ if (isGroupField(groupField) && groupField.config.fields[fieldId]) {
185
+ console.error(`Field "${fieldId}" already exists in group "${groupFieldId}" in tab "${tabName}"`);
186
+ process.exitCode = 1;
187
+ return;
188
+ }
189
+ }
190
+ }
191
+ model.json[targetTab][fieldId] = fieldDefinition;
192
+ }
163
193
 
164
194
  // Write updated model
165
195
  try {
@@ -174,7 +204,11 @@ export async function pageTypeAddFieldSelect(): Promise<void> {
174
204
  return;
175
205
  }
176
206
 
177
- console.info(`Added field "${fieldId}" (Select) to "${targetTab}" tab in ${typeId}`);
207
+ if (fieldPath.type === "nested") {
208
+ console.info(`Added field "${fieldPath.nestedFieldId}" (Select) to group "${fieldPath.groupId}" in ${typeId}`);
209
+ } else {
210
+ console.info(`Added field "${fieldId}" (Select) to "${targetTab}" tab in ${typeId}`);
211
+ }
178
212
 
179
213
  try {
180
214
  await buildTypes({ output: types });
@@ -190,7 +224,7 @@ export async function pageTypeAddFieldSelect(): Promise<void> {
190
224
  if (frameworkInfo?.framework) {
191
225
  const docsPath = getDocsPath(frameworkInfo.framework);
192
226
  console.info(
193
- ` Run \`prismic docs ${docsPath}#write-page-components\` to learn how to implement a page file`,
227
+ ` Run \`prismic docs fetch ${docsPath}#write-page-components\` to learn how to implement a page file`,
194
228
  );
195
229
  }
196
230
  }