@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
@@ -4,6 +4,7 @@ import { writeFile } from "node:fs/promises";
4
4
  import { parseArgs } from "node:util";
5
5
 
6
6
  import { buildTypes } from "./codegen-types";
7
+ import { findGroupInVariation, isGroupField, parseFieldPath, validateNestedFieldPath } from "./lib/field-path";
7
8
  import { type Framework, detectFrameworkInfo } from "./lib/framework";
8
9
  import { stringify } from "./lib/json";
9
10
  import { findSliceModel } from "./lib/slice";
@@ -105,6 +106,15 @@ export async function sliceAddFieldLink(): Promise<void> {
105
106
  return;
106
107
  }
107
108
 
109
+ // Parse and validate field path
110
+ const fieldPath = parseFieldPath(fieldId);
111
+ const pathValidation = validateNestedFieldPath(fieldPath);
112
+ if (!pathValidation.ok) {
113
+ console.error(pathValidation.error);
114
+ process.exitCode = 1;
115
+ return;
116
+ }
117
+
108
118
  // Find the slice model
109
119
  const result = await findSliceModel(sliceId);
110
120
  if (!result.ok) {
@@ -140,20 +150,11 @@ export async function sliceAddFieldLink(): Promise<void> {
140
150
  targetVariation.primary = {};
141
151
  }
142
152
 
143
- // Check if field already exists in any variation
144
- for (const v of model.variations) {
145
- if (v.primary?.[fieldId]) {
146
- console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
147
- process.exitCode = 1;
148
- return;
149
- }
150
- }
151
-
152
153
  // Build field definition
153
154
  const fieldDefinition: Link = {
154
155
  type: "Link",
155
156
  config: {
156
- label: label ?? humanReadable(fieldId),
157
+ label: label ?? humanReadable(fieldPath.type === "nested" ? fieldPath.nestedFieldId : fieldId),
157
158
  ...(placeholder && { placeholder }),
158
159
  ...(allowText && { allowText: true }),
159
160
  ...(allowTargetBlank && { allowTargetBlank: true }),
@@ -161,8 +162,44 @@ export async function sliceAddFieldLink(): Promise<void> {
161
162
  },
162
163
  };
163
164
 
164
- // Add field to variation
165
- targetVariation.primary[fieldId] = fieldDefinition;
165
+ // Add field to variation (with nested field support)
166
+ if (fieldPath.type === "nested") {
167
+ const groupResult = findGroupInVariation(targetVariation.primary, fieldPath.groupId, targetVariation.id);
168
+ if (!groupResult.ok) {
169
+ console.error(groupResult.error);
170
+ process.exitCode = 1;
171
+ return;
172
+ }
173
+ // Check if nested field already exists
174
+ if (groupResult.group.config.fields[fieldPath.nestedFieldId]) {
175
+ console.error(
176
+ `Field "${fieldPath.nestedFieldId}" already exists in group "${fieldPath.groupId}"`,
177
+ );
178
+ process.exitCode = 1;
179
+ return;
180
+ }
181
+ groupResult.group.config.fields[fieldPath.nestedFieldId] = fieldDefinition;
182
+ } else {
183
+ // Check if field already exists in any variation (at top level or in groups)
184
+ for (const v of model.variations) {
185
+ if (v.primary?.[fieldId]) {
186
+ console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
187
+ process.exitCode = 1;
188
+ return;
189
+ }
190
+ // Also check inside groups
191
+ for (const [groupFieldId, groupField] of Object.entries(v.primary ?? {})) {
192
+ if (isGroupField(groupField) && groupField.config.fields[fieldId]) {
193
+ console.error(
194
+ `Field "${fieldId}" already exists in group "${groupFieldId}" in variation "${v.id}"`,
195
+ );
196
+ process.exitCode = 1;
197
+ return;
198
+ }
199
+ }
200
+ }
201
+ targetVariation.primary[fieldId] = fieldDefinition;
202
+ }
166
203
 
167
204
  // Write updated model
168
205
  try {
@@ -177,9 +214,15 @@ export async function sliceAddFieldLink(): Promise<void> {
177
214
  return;
178
215
  }
179
216
 
180
- console.info(
181
- `Added field "${fieldId}" (Link) to "${targetVariation.id}" variation in ${sliceId}`,
182
- );
217
+ if (fieldPath.type === "nested") {
218
+ console.info(
219
+ `Added field "${fieldPath.nestedFieldId}" (Link) to group "${fieldPath.groupId}" in ${sliceId}`,
220
+ );
221
+ } else {
222
+ console.info(
223
+ `Added field "${fieldId}" (Link) to "${targetVariation.id}" variation in ${sliceId}`,
224
+ );
225
+ }
183
226
 
184
227
  try {
185
228
  await buildTypes({ output: types });
@@ -196,7 +239,7 @@ export async function sliceAddFieldLink(): Promise<void> {
196
239
  const docsPath = getDocsPath(frameworkInfo.framework);
197
240
  const anchor = getWriteComponentsAnchor(frameworkInfo.framework);
198
241
  console.info(
199
- ` Run \`prismic docs ${docsPath}${anchor}\` to learn how to implement the slice's component`,
242
+ ` Run \`prismic docs fetch ${docsPath}${anchor}\` to learn how to implement the slice's component`,
200
243
  );
201
244
  }
202
245
  }
@@ -4,6 +4,7 @@ import { writeFile } from "node:fs/promises";
4
4
  import { parseArgs } from "node:util";
5
5
 
6
6
  import { buildTypes } from "./codegen-types";
7
+ import { findGroupInVariation, isGroupField, parseFieldPath, validateNestedFieldPath } from "./lib/field-path";
7
8
  import { type Framework, detectFrameworkInfo } from "./lib/framework";
8
9
  import { stringify } from "./lib/json";
9
10
  import { findSliceModel } from "./lib/slice";
@@ -89,6 +90,15 @@ export async function sliceAddFieldNumber(): Promise<void> {
89
90
  return;
90
91
  }
91
92
 
93
+ // Parse and validate field path
94
+ const fieldPath = parseFieldPath(fieldId);
95
+ const pathValidation = validateNestedFieldPath(fieldPath);
96
+ if (!pathValidation.ok) {
97
+ console.error(pathValidation.error);
98
+ process.exitCode = 1;
99
+ return;
100
+ }
101
+
92
102
  // Find the slice model
93
103
  const result = await findSliceModel(sliceId);
94
104
  if (!result.ok) {
@@ -124,26 +134,53 @@ export async function sliceAddFieldNumber(): Promise<void> {
124
134
  targetVariation.primary = {};
125
135
  }
126
136
 
127
- // Check if field already exists in any variation
128
- for (const v of model.variations) {
129
- if (v.primary?.[fieldId]) {
130
- console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
131
- process.exitCode = 1;
132
- return;
133
- }
134
- }
135
-
136
137
  // Build field definition
137
138
  const fieldDefinition: Number = {
138
139
  type: "Number",
139
140
  config: {
140
- label: label ?? humanReadable(fieldId),
141
+ label: label ?? humanReadable(fieldPath.type === "nested" ? fieldPath.nestedFieldId : fieldId),
141
142
  ...(placeholder && { placeholder }),
142
143
  },
143
144
  };
144
145
 
145
- // Add field to variation
146
- targetVariation.primary[fieldId] = fieldDefinition;
146
+ // Add field to variation (with nested field support)
147
+ if (fieldPath.type === "nested") {
148
+ const groupResult = findGroupInVariation(targetVariation.primary, fieldPath.groupId, targetVariation.id);
149
+ if (!groupResult.ok) {
150
+ console.error(groupResult.error);
151
+ process.exitCode = 1;
152
+ return;
153
+ }
154
+ // Check if nested field already exists
155
+ if (groupResult.group.config.fields[fieldPath.nestedFieldId]) {
156
+ console.error(
157
+ `Field "${fieldPath.nestedFieldId}" already exists in group "${fieldPath.groupId}"`,
158
+ );
159
+ process.exitCode = 1;
160
+ return;
161
+ }
162
+ groupResult.group.config.fields[fieldPath.nestedFieldId] = fieldDefinition;
163
+ } else {
164
+ // Check if field already exists in any variation (at top level or in groups)
165
+ for (const v of model.variations) {
166
+ if (v.primary?.[fieldId]) {
167
+ console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
168
+ process.exitCode = 1;
169
+ return;
170
+ }
171
+ // Also check inside groups
172
+ for (const [groupFieldId, groupField] of Object.entries(v.primary ?? {})) {
173
+ if (isGroupField(groupField) && groupField.config.fields[fieldId]) {
174
+ console.error(
175
+ `Field "${fieldId}" already exists in group "${groupFieldId}" in variation "${v.id}"`,
176
+ );
177
+ process.exitCode = 1;
178
+ return;
179
+ }
180
+ }
181
+ }
182
+ targetVariation.primary[fieldId] = fieldDefinition;
183
+ }
147
184
 
148
185
  // Write updated model
149
186
  try {
@@ -158,9 +195,15 @@ export async function sliceAddFieldNumber(): Promise<void> {
158
195
  return;
159
196
  }
160
197
 
161
- console.info(
162
- `Added field "${fieldId}" (Number) to "${targetVariation.id}" variation in ${sliceId}`,
163
- );
198
+ if (fieldPath.type === "nested") {
199
+ console.info(
200
+ `Added field "${fieldPath.nestedFieldId}" (Number) to group "${fieldPath.groupId}" in ${sliceId}`,
201
+ );
202
+ } else {
203
+ console.info(
204
+ `Added field "${fieldId}" (Number) to "${targetVariation.id}" variation in ${sliceId}`,
205
+ );
206
+ }
164
207
 
165
208
  try {
166
209
  await buildTypes({ output: types });
@@ -177,7 +220,7 @@ export async function sliceAddFieldNumber(): Promise<void> {
177
220
  const docsPath = getDocsPath(frameworkInfo.framework);
178
221
  const anchor = getWriteComponentsAnchor(frameworkInfo.framework);
179
222
  console.info(
180
- ` Run \`prismic docs ${docsPath}${anchor}\` to learn how to implement the slice's component`,
223
+ ` Run \`prismic docs fetch ${docsPath}${anchor}\` to learn how to implement the slice's component`,
181
224
  );
182
225
  }
183
226
  }
@@ -4,6 +4,7 @@ import { writeFile } from "node:fs/promises";
4
4
  import { parseArgs } from "node:util";
5
5
 
6
6
  import { buildTypes } from "./codegen-types";
7
+ import { findGroupInVariation, isGroupField, parseFieldPath, validateNestedFieldPath } from "./lib/field-path";
7
8
  import { type Framework, detectFrameworkInfo } from "./lib/framework";
8
9
  import { stringify } from "./lib/json";
9
10
  import { findSliceModel } from "./lib/slice";
@@ -110,6 +111,15 @@ export async function sliceAddFieldRichText(): Promise<void> {
110
111
  return;
111
112
  }
112
113
 
114
+ // Parse and validate field path
115
+ const fieldPath = parseFieldPath(fieldId);
116
+ const pathValidation = validateNestedFieldPath(fieldPath);
117
+ if (!pathValidation.ok) {
118
+ console.error(pathValidation.error);
119
+ process.exitCode = 1;
120
+ return;
121
+ }
122
+
113
123
  // Find the slice model
114
124
  const result = await findSliceModel(sliceId);
115
125
  if (!result.ok) {
@@ -145,20 +155,11 @@ export async function sliceAddFieldRichText(): Promise<void> {
145
155
  targetVariation.primary = {};
146
156
  }
147
157
 
148
- // Check if field already exists in any variation
149
- for (const v of model.variations) {
150
- if (v.primary?.[fieldId]) {
151
- console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
152
- process.exitCode = 1;
153
- return;
154
- }
155
- }
156
-
157
158
  // Build field definition
158
159
  const fieldDefinition: RichText = {
159
160
  type: "StructuredText",
160
161
  config: {
161
- label: label ?? humanReadable(fieldId),
162
+ label: label ?? humanReadable(fieldPath.type === "nested" ? fieldPath.nestedFieldId : fieldId),
162
163
  ...(placeholder && { placeholder }),
163
164
  ...(single && { single }),
164
165
  ...(multi && { multi }),
@@ -166,8 +167,44 @@ export async function sliceAddFieldRichText(): Promise<void> {
166
167
  },
167
168
  };
168
169
 
169
- // Add field to variation
170
- targetVariation.primary[fieldId] = fieldDefinition;
170
+ // Add field to variation (with nested field support)
171
+ if (fieldPath.type === "nested") {
172
+ const groupResult = findGroupInVariation(targetVariation.primary, fieldPath.groupId, targetVariation.id);
173
+ if (!groupResult.ok) {
174
+ console.error(groupResult.error);
175
+ process.exitCode = 1;
176
+ return;
177
+ }
178
+ // Check if nested field already exists
179
+ if (groupResult.group.config.fields[fieldPath.nestedFieldId]) {
180
+ console.error(
181
+ `Field "${fieldPath.nestedFieldId}" already exists in group "${fieldPath.groupId}"`,
182
+ );
183
+ process.exitCode = 1;
184
+ return;
185
+ }
186
+ groupResult.group.config.fields[fieldPath.nestedFieldId] = fieldDefinition;
187
+ } else {
188
+ // Check if field already exists in any variation (at top level or in groups)
189
+ for (const v of model.variations) {
190
+ if (v.primary?.[fieldId]) {
191
+ console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
192
+ process.exitCode = 1;
193
+ return;
194
+ }
195
+ // Also check inside groups
196
+ for (const [groupFieldId, groupField] of Object.entries(v.primary ?? {})) {
197
+ if (isGroupField(groupField) && groupField.config.fields[fieldId]) {
198
+ console.error(
199
+ `Field "${fieldId}" already exists in group "${groupFieldId}" in variation "${v.id}"`,
200
+ );
201
+ process.exitCode = 1;
202
+ return;
203
+ }
204
+ }
205
+ }
206
+ targetVariation.primary[fieldId] = fieldDefinition;
207
+ }
171
208
 
172
209
  // Write updated model
173
210
  try {
@@ -182,9 +219,15 @@ export async function sliceAddFieldRichText(): Promise<void> {
182
219
  return;
183
220
  }
184
221
 
185
- console.info(
186
- `Added field "${fieldId}" (StructuredText) to "${targetVariation.id}" variation in ${sliceId}`,
187
- );
222
+ if (fieldPath.type === "nested") {
223
+ console.info(
224
+ `Added field "${fieldPath.nestedFieldId}" (StructuredText) to group "${fieldPath.groupId}" in ${sliceId}`,
225
+ );
226
+ } else {
227
+ console.info(
228
+ `Added field "${fieldId}" (StructuredText) to "${targetVariation.id}" variation in ${sliceId}`,
229
+ );
230
+ }
188
231
 
189
232
  try {
190
233
  await buildTypes({ output: types });
@@ -201,7 +244,7 @@ export async function sliceAddFieldRichText(): Promise<void> {
201
244
  const docsPath = getDocsPath(frameworkInfo.framework);
202
245
  const anchor = getWriteComponentsAnchor(frameworkInfo.framework);
203
246
  console.info(
204
- ` Run \`prismic docs ${docsPath}${anchor}\` to learn how to implement the slice's component`,
247
+ ` Run \`prismic docs fetch ${docsPath}${anchor}\` to learn how to implement the slice's component`,
205
248
  );
206
249
  }
207
250
  }
@@ -4,6 +4,7 @@ import { writeFile } from "node:fs/promises";
4
4
  import { parseArgs } from "node:util";
5
5
 
6
6
  import { buildTypes } from "./codegen-types";
7
+ import { findGroupInVariation, isGroupField, parseFieldPath, validateNestedFieldPath } from "./lib/field-path";
7
8
  import { type Framework, detectFrameworkInfo } from "./lib/framework";
8
9
  import { stringify } from "./lib/json";
9
10
  import { findSliceModel } from "./lib/slice";
@@ -93,6 +94,15 @@ export async function sliceAddFieldSelect(): Promise<void> {
93
94
  return;
94
95
  }
95
96
 
97
+ // Parse and validate field path
98
+ const fieldPath = parseFieldPath(fieldId);
99
+ const pathValidation = validateNestedFieldPath(fieldPath);
100
+ if (!pathValidation.ok) {
101
+ console.error(pathValidation.error);
102
+ process.exitCode = 1;
103
+ return;
104
+ }
105
+
96
106
  // Find the slice model
97
107
  const result = await findSliceModel(sliceId);
98
108
  if (!result.ok) {
@@ -128,28 +138,55 @@ export async function sliceAddFieldSelect(): Promise<void> {
128
138
  targetVariation.primary = {};
129
139
  }
130
140
 
131
- // Check if field already exists in any variation
132
- for (const v of model.variations) {
133
- if (v.primary?.[fieldId]) {
134
- console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
135
- process.exitCode = 1;
136
- return;
137
- }
138
- }
139
-
140
141
  // Build field definition
141
142
  const fieldDefinition: Select = {
142
143
  type: "Select",
143
144
  config: {
144
- label: label ?? humanReadable(fieldId),
145
+ label: label ?? humanReadable(fieldPath.type === "nested" ? fieldPath.nestedFieldId : fieldId),
145
146
  ...(placeholder && { placeholder }),
146
147
  ...(option && option.length > 0 && { options: option }),
147
148
  ...(defaultValue && { default_value: defaultValue }),
148
149
  },
149
150
  };
150
151
 
151
- // Add field to variation
152
- targetVariation.primary[fieldId] = fieldDefinition;
152
+ // Add field to variation (with nested field support)
153
+ if (fieldPath.type === "nested") {
154
+ const groupResult = findGroupInVariation(targetVariation.primary, fieldPath.groupId, targetVariation.id);
155
+ if (!groupResult.ok) {
156
+ console.error(groupResult.error);
157
+ process.exitCode = 1;
158
+ return;
159
+ }
160
+ // Check if nested field already exists
161
+ if (groupResult.group.config.fields[fieldPath.nestedFieldId]) {
162
+ console.error(
163
+ `Field "${fieldPath.nestedFieldId}" already exists in group "${fieldPath.groupId}"`,
164
+ );
165
+ process.exitCode = 1;
166
+ return;
167
+ }
168
+ groupResult.group.config.fields[fieldPath.nestedFieldId] = fieldDefinition;
169
+ } else {
170
+ // Check if field already exists in any variation (at top level or in groups)
171
+ for (const v of model.variations) {
172
+ if (v.primary?.[fieldId]) {
173
+ console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
174
+ process.exitCode = 1;
175
+ return;
176
+ }
177
+ // Also check inside groups
178
+ for (const [groupFieldId, groupField] of Object.entries(v.primary ?? {})) {
179
+ if (isGroupField(groupField) && groupField.config.fields[fieldId]) {
180
+ console.error(
181
+ `Field "${fieldId}" already exists in group "${groupFieldId}" in variation "${v.id}"`,
182
+ );
183
+ process.exitCode = 1;
184
+ return;
185
+ }
186
+ }
187
+ }
188
+ targetVariation.primary[fieldId] = fieldDefinition;
189
+ }
153
190
 
154
191
  // Write updated model
155
192
  try {
@@ -164,9 +201,15 @@ export async function sliceAddFieldSelect(): Promise<void> {
164
201
  return;
165
202
  }
166
203
 
167
- console.info(
168
- `Added field "${fieldId}" (Select) to "${targetVariation.id}" variation in ${sliceId}`,
169
- );
204
+ if (fieldPath.type === "nested") {
205
+ console.info(
206
+ `Added field "${fieldPath.nestedFieldId}" (Select) to group "${fieldPath.groupId}" in ${sliceId}`,
207
+ );
208
+ } else {
209
+ console.info(
210
+ `Added field "${fieldId}" (Select) to "${targetVariation.id}" variation in ${sliceId}`,
211
+ );
212
+ }
170
213
 
171
214
  try {
172
215
  await buildTypes({ output: types });
@@ -183,7 +226,7 @@ export async function sliceAddFieldSelect(): Promise<void> {
183
226
  const docsPath = getDocsPath(frameworkInfo.framework);
184
227
  const anchor = getWriteComponentsAnchor(frameworkInfo.framework);
185
228
  console.info(
186
- ` Run \`prismic docs ${docsPath}${anchor}\` to learn how to implement the slice's component`,
229
+ ` Run \`prismic docs fetch ${docsPath}${anchor}\` to learn how to implement the slice's component`,
187
230
  );
188
231
  }
189
232
  }
@@ -4,6 +4,7 @@ import { writeFile } from "node:fs/promises";
4
4
  import { parseArgs } from "node:util";
5
5
 
6
6
  import { buildTypes } from "./codegen-types";
7
+ import { findGroupInVariation, isGroupField, parseFieldPath, validateNestedFieldPath } from "./lib/field-path";
7
8
  import { type Framework, detectFrameworkInfo } from "./lib/framework";
8
9
  import { stringify } from "./lib/json";
9
10
  import { findSliceModel } from "./lib/slice";
@@ -89,6 +90,15 @@ export async function sliceAddFieldTimestamp(): Promise<void> {
89
90
  return;
90
91
  }
91
92
 
93
+ // Parse and validate field path
94
+ const fieldPath = parseFieldPath(fieldId);
95
+ const pathValidation = validateNestedFieldPath(fieldPath);
96
+ if (!pathValidation.ok) {
97
+ console.error(pathValidation.error);
98
+ process.exitCode = 1;
99
+ return;
100
+ }
101
+
92
102
  // Find the slice model
93
103
  const result = await findSliceModel(sliceId);
94
104
  if (!result.ok) {
@@ -124,26 +134,53 @@ export async function sliceAddFieldTimestamp(): Promise<void> {
124
134
  targetVariation.primary = {};
125
135
  }
126
136
 
127
- // Check if field already exists in any variation
128
- for (const v of model.variations) {
129
- if (v.primary?.[fieldId]) {
130
- console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
131
- process.exitCode = 1;
132
- return;
133
- }
134
- }
135
-
136
137
  // Build field definition
137
138
  const fieldDefinition: Timestamp = {
138
139
  type: "Timestamp",
139
140
  config: {
140
- label: label ?? humanReadable(fieldId),
141
+ label: label ?? humanReadable(fieldPath.type === "nested" ? fieldPath.nestedFieldId : fieldId),
141
142
  ...(placeholder && { placeholder }),
142
143
  },
143
144
  };
144
145
 
145
- // Add field to variation
146
- targetVariation.primary[fieldId] = fieldDefinition;
146
+ // Add field to variation (with nested field support)
147
+ if (fieldPath.type === "nested") {
148
+ const groupResult = findGroupInVariation(targetVariation.primary, fieldPath.groupId, targetVariation.id);
149
+ if (!groupResult.ok) {
150
+ console.error(groupResult.error);
151
+ process.exitCode = 1;
152
+ return;
153
+ }
154
+ // Check if nested field already exists
155
+ if (groupResult.group.config.fields[fieldPath.nestedFieldId]) {
156
+ console.error(
157
+ `Field "${fieldPath.nestedFieldId}" already exists in group "${fieldPath.groupId}"`,
158
+ );
159
+ process.exitCode = 1;
160
+ return;
161
+ }
162
+ groupResult.group.config.fields[fieldPath.nestedFieldId] = fieldDefinition;
163
+ } else {
164
+ // Check if field already exists in any variation (at top level or in groups)
165
+ for (const v of model.variations) {
166
+ if (v.primary?.[fieldId]) {
167
+ console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
168
+ process.exitCode = 1;
169
+ return;
170
+ }
171
+ // Also check inside groups
172
+ for (const [groupFieldId, groupField] of Object.entries(v.primary ?? {})) {
173
+ if (isGroupField(groupField) && groupField.config.fields[fieldId]) {
174
+ console.error(
175
+ `Field "${fieldId}" already exists in group "${groupFieldId}" in variation "${v.id}"`,
176
+ );
177
+ process.exitCode = 1;
178
+ return;
179
+ }
180
+ }
181
+ }
182
+ targetVariation.primary[fieldId] = fieldDefinition;
183
+ }
147
184
 
148
185
  // Write updated model
149
186
  try {
@@ -158,9 +195,15 @@ export async function sliceAddFieldTimestamp(): Promise<void> {
158
195
  return;
159
196
  }
160
197
 
161
- console.info(
162
- `Added field "${fieldId}" (Timestamp) to "${targetVariation.id}" variation in ${sliceId}`,
163
- );
198
+ if (fieldPath.type === "nested") {
199
+ console.info(
200
+ `Added field "${fieldPath.nestedFieldId}" (Timestamp) to group "${fieldPath.groupId}" in ${sliceId}`,
201
+ );
202
+ } else {
203
+ console.info(
204
+ `Added field "${fieldId}" (Timestamp) to "${targetVariation.id}" variation in ${sliceId}`,
205
+ );
206
+ }
164
207
 
165
208
  try {
166
209
  await buildTypes({ output: types });
@@ -177,7 +220,7 @@ export async function sliceAddFieldTimestamp(): Promise<void> {
177
220
  const docsPath = getDocsPath(frameworkInfo.framework);
178
221
  const anchor = getWriteComponentsAnchor(frameworkInfo.framework);
179
222
  console.info(
180
- ` Run \`prismic docs ${docsPath}${anchor}\` to learn how to implement the slice's component`,
223
+ ` Run \`prismic docs fetch ${docsPath}${anchor}\` to learn how to implement the slice's component`,
181
224
  );
182
225
  }
183
226
  }
@@ -5,6 +5,7 @@ import { sliceAddFieldColor } from "./slice-add-field-color";
5
5
  import { sliceAddFieldDate } from "./slice-add-field-date";
6
6
  import { sliceAddFieldEmbed } from "./slice-add-field-embed";
7
7
  import { sliceAddFieldGeoPoint } from "./slice-add-field-geo-point";
8
+ import { sliceAddFieldGroup } from "./slice-add-field-group";
8
9
  import { sliceAddFieldImage } from "./slice-add-field-image";
9
10
  import { sliceAddFieldKeyText } from "./slice-add-field-key-text";
10
11
  import { sliceAddFieldLink } from "./slice-add-field-link";
@@ -25,6 +26,7 @@ FIELD TYPES
25
26
  date Date picker
26
27
  embed Embed (oEmbed)
27
28
  geo-point Geographic coordinates
29
+ group Repeatable group of fields
28
30
  image Image
29
31
  key-text Single-line text
30
32
  link Any link type
@@ -74,6 +76,9 @@ export async function sliceAddField(): Promise<void> {
74
76
  case "geo-point":
75
77
  await sliceAddFieldGeoPoint();
76
78
  break;
79
+ case "group":
80
+ await sliceAddFieldGroup();
81
+ break;
77
82
  case "image":
78
83
  await sliceAddFieldImage();
79
84
  break;
package/src/status.ts CHANGED
@@ -83,7 +83,7 @@ function getDocsPath(framework: Framework | undefined): string {
83
83
  function getDocsRef(docsPath: string, anchor?: string): string {
84
84
  if (!docsPath) return "";
85
85
  const fullPath = anchor ? `${docsPath}${anchor}` : docsPath;
86
- return `\`prismic docs ${fullPath}\``;
86
+ return `\`prismic docs fetch ${fullPath}\``;
87
87
  }
88
88
 
89
89
  function getClientSetupAnchor(framework: Framework | undefined): string {