@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.
- package/dist/index.mjs +229 -136
- 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 +46 -12
- 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/docs-fetch.ts +146 -0
- package/src/docs-list.ts +131 -0
- package/src/docs.ts +26 -121
- package/src/index.ts +1 -1
- package/src/lib/field-path.ts +81 -0
- package/src/page-type-add-field-boolean.ts +47 -13
- package/src/page-type-add-field-color.ts +47 -13
- package/src/page-type-add-field-date.ts +47 -13
- package/src/page-type-add-field-embed.ts +47 -13
- package/src/page-type-add-field-geo-point.ts +47 -13
- package/src/page-type-add-field-group.ts +198 -0
- package/src/page-type-add-field-image.ts +47 -13
- package/src/page-type-add-field-key-text.ts +47 -13
- package/src/page-type-add-field-link.ts +47 -13
- package/src/page-type-add-field-number.ts +47 -13
- package/src/page-type-add-field-rich-text.ts +47 -13
- package/src/page-type-add-field-select.ts +47 -13
- package/src/page-type-add-field-timestamp.ts +47 -13
- package/src/page-type-add-field-uid.ts +18 -1
- package/src/page-type-add-field.ts +5 -0
- package/src/page-type-create.ts +1 -1
- package/src/repo-create.ts +28 -1
- package/src/slice-add-field-boolean.ts +59 -16
- package/src/slice-add-field-color.ts +59 -16
- package/src/slice-add-field-date.ts +59 -16
- package/src/slice-add-field-embed.ts +59 -16
- package/src/slice-add-field-geo-point.ts +59 -16
- package/src/slice-add-field-group.ts +191 -0
- package/src/slice-add-field-image.ts +59 -16
- package/src/slice-add-field-key-text.ts +59 -16
- package/src/slice-add-field-link.ts +59 -16
- package/src/slice-add-field-number.ts +59 -16
- package/src/slice-add-field-rich-text.ts +59 -16
- package/src/slice-add-field-select.ts +59 -16
- package/src/slice-add-field-timestamp.ts +59 -16
- package/src/slice-add-field.ts +5 -0
- 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";
|
|
@@ -89,6 +90,15 @@ export async function sliceAddFieldEmbed(): 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 sliceAddFieldEmbed(): 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: Embed = {
|
|
138
139
|
type: "Embed",
|
|
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
|
-
|
|
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 sliceAddFieldEmbed(): Promise<void> {
|
|
|
158
195
|
return;
|
|
159
196
|
}
|
|
160
197
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
198
|
+
if (fieldPath.type === "nested") {
|
|
199
|
+
console.info(
|
|
200
|
+
`Added field "${fieldPath.nestedFieldId}" (Embed) to group "${fieldPath.groupId}" in ${sliceId}`,
|
|
201
|
+
);
|
|
202
|
+
} else {
|
|
203
|
+
console.info(
|
|
204
|
+
`Added field "${fieldId}" (Embed) 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 sliceAddFieldEmbed(): 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";
|
|
@@ -87,6 +88,15 @@ export async function sliceAddFieldGeoPoint(): Promise<void> {
|
|
|
87
88
|
return;
|
|
88
89
|
}
|
|
89
90
|
|
|
91
|
+
// Parse and validate field path
|
|
92
|
+
const fieldPath = parseFieldPath(fieldId);
|
|
93
|
+
const pathValidation = validateNestedFieldPath(fieldPath);
|
|
94
|
+
if (!pathValidation.ok) {
|
|
95
|
+
console.error(pathValidation.error);
|
|
96
|
+
process.exitCode = 1;
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
90
100
|
// Find the slice model
|
|
91
101
|
const result = await findSliceModel(sliceId);
|
|
92
102
|
if (!result.ok) {
|
|
@@ -122,25 +132,52 @@ export async function sliceAddFieldGeoPoint(): Promise<void> {
|
|
|
122
132
|
targetVariation.primary = {};
|
|
123
133
|
}
|
|
124
134
|
|
|
125
|
-
// Check if field already exists in any variation
|
|
126
|
-
for (const v of model.variations) {
|
|
127
|
-
if (v.primary?.[fieldId]) {
|
|
128
|
-
console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
|
|
129
|
-
process.exitCode = 1;
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
135
|
// Build field definition
|
|
135
136
|
const fieldDefinition: GeoPoint = {
|
|
136
137
|
type: "GeoPoint",
|
|
137
138
|
config: {
|
|
138
|
-
label: label ?? humanReadable(fieldId),
|
|
139
|
+
label: label ?? humanReadable(fieldPath.type === "nested" ? fieldPath.nestedFieldId : fieldId),
|
|
139
140
|
},
|
|
140
141
|
};
|
|
141
142
|
|
|
142
|
-
// Add field to variation
|
|
143
|
-
|
|
143
|
+
// Add field to variation (with nested field support)
|
|
144
|
+
if (fieldPath.type === "nested") {
|
|
145
|
+
const groupResult = findGroupInVariation(targetVariation.primary, fieldPath.groupId, targetVariation.id);
|
|
146
|
+
if (!groupResult.ok) {
|
|
147
|
+
console.error(groupResult.error);
|
|
148
|
+
process.exitCode = 1;
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
// Check if nested field already exists
|
|
152
|
+
if (groupResult.group.config.fields[fieldPath.nestedFieldId]) {
|
|
153
|
+
console.error(
|
|
154
|
+
`Field "${fieldPath.nestedFieldId}" already exists in group "${fieldPath.groupId}"`,
|
|
155
|
+
);
|
|
156
|
+
process.exitCode = 1;
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
groupResult.group.config.fields[fieldPath.nestedFieldId] = fieldDefinition;
|
|
160
|
+
} else {
|
|
161
|
+
// Check if field already exists in any variation (at top level or in groups)
|
|
162
|
+
for (const v of model.variations) {
|
|
163
|
+
if (v.primary?.[fieldId]) {
|
|
164
|
+
console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
|
|
165
|
+
process.exitCode = 1;
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
// Also check inside groups
|
|
169
|
+
for (const [groupFieldId, groupField] of Object.entries(v.primary ?? {})) {
|
|
170
|
+
if (isGroupField(groupField) && groupField.config.fields[fieldId]) {
|
|
171
|
+
console.error(
|
|
172
|
+
`Field "${fieldId}" already exists in group "${groupFieldId}" in variation "${v.id}"`,
|
|
173
|
+
);
|
|
174
|
+
process.exitCode = 1;
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
targetVariation.primary[fieldId] = fieldDefinition;
|
|
180
|
+
}
|
|
144
181
|
|
|
145
182
|
// Write updated model
|
|
146
183
|
try {
|
|
@@ -155,9 +192,15 @@ export async function sliceAddFieldGeoPoint(): Promise<void> {
|
|
|
155
192
|
return;
|
|
156
193
|
}
|
|
157
194
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
195
|
+
if (fieldPath.type === "nested") {
|
|
196
|
+
console.info(
|
|
197
|
+
`Added field "${fieldPath.nestedFieldId}" (GeoPoint) to group "${fieldPath.groupId}" in ${sliceId}`,
|
|
198
|
+
);
|
|
199
|
+
} else {
|
|
200
|
+
console.info(
|
|
201
|
+
`Added field "${fieldId}" (GeoPoint) to "${targetVariation.id}" variation in ${sliceId}`,
|
|
202
|
+
);
|
|
203
|
+
}
|
|
161
204
|
|
|
162
205
|
try {
|
|
163
206
|
await buildTypes({ output: types });
|
|
@@ -174,7 +217,7 @@ export async function sliceAddFieldGeoPoint(): Promise<void> {
|
|
|
174
217
|
const docsPath = getDocsPath(frameworkInfo.framework);
|
|
175
218
|
const anchor = getWriteComponentsAnchor(frameworkInfo.framework);
|
|
176
219
|
console.info(
|
|
177
|
-
` Run \`prismic docs ${docsPath}${anchor}\` to learn how to implement the slice's component`,
|
|
220
|
+
` Run \`prismic docs fetch ${docsPath}${anchor}\` to learn how to implement the slice's component`,
|
|
178
221
|
);
|
|
179
222
|
}
|
|
180
223
|
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import type { Group, SharedSlice } from "@prismicio/types-internal/lib/customtypes";
|
|
2
|
+
|
|
3
|
+
import { writeFile } from "node:fs/promises";
|
|
4
|
+
import { parseArgs } from "node:util";
|
|
5
|
+
|
|
6
|
+
import { buildTypes } from "./codegen-types";
|
|
7
|
+
import { type Framework, detectFrameworkInfo } from "./lib/framework";
|
|
8
|
+
import { stringify } from "./lib/json";
|
|
9
|
+
import { findSliceModel } from "./lib/slice";
|
|
10
|
+
import { humanReadable } from "./lib/string";
|
|
11
|
+
|
|
12
|
+
const HELP = `
|
|
13
|
+
Add a group field to an existing slice.
|
|
14
|
+
|
|
15
|
+
USAGE
|
|
16
|
+
prismic slice add-field group <slice-id> <field-id> [flags]
|
|
17
|
+
|
|
18
|
+
ARGUMENTS
|
|
19
|
+
slice-id Slice identifier (required)
|
|
20
|
+
field-id Field identifier (required)
|
|
21
|
+
|
|
22
|
+
FLAGS
|
|
23
|
+
-v, --variation string Target variation (default: first variation)
|
|
24
|
+
-l, --label string Display label for the field (inferred from field-id if omitted)
|
|
25
|
+
--non-repeatable Make this a non-repeating group (default: repeatable)
|
|
26
|
+
--types string Output file for generated types (default: "prismicio-types.d.ts")
|
|
27
|
+
-h, --help Show help for command
|
|
28
|
+
|
|
29
|
+
EXAMPLES
|
|
30
|
+
prismic slice add-field group my_slice buttons
|
|
31
|
+
prismic slice add-field group hero ctas --non-repeatable
|
|
32
|
+
prismic slice add-field group product variants --variation "withImage"
|
|
33
|
+
`.trim();
|
|
34
|
+
|
|
35
|
+
function getDocsPath(framework: Framework): string {
|
|
36
|
+
switch (framework) {
|
|
37
|
+
case "next":
|
|
38
|
+
return "nextjs/with-cli";
|
|
39
|
+
case "nuxt":
|
|
40
|
+
return "nuxt/with-cli";
|
|
41
|
+
case "sveltekit":
|
|
42
|
+
return "sveltekit/with-cli";
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function getWriteComponentsAnchor(framework: Framework): string {
|
|
47
|
+
switch (framework) {
|
|
48
|
+
case "nuxt":
|
|
49
|
+
return "#write-vue-components";
|
|
50
|
+
case "sveltekit":
|
|
51
|
+
return "#write-svelte-components";
|
|
52
|
+
default:
|
|
53
|
+
return "#write-react-components";
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export async function sliceAddFieldGroup(): Promise<void> {
|
|
58
|
+
const {
|
|
59
|
+
values: { help, variation, label, "non-repeatable": nonRepeatable, types },
|
|
60
|
+
positionals: [sliceId, fieldId],
|
|
61
|
+
} = parseArgs({
|
|
62
|
+
args: process.argv.slice(5), // skip: node, script, "slice", "add-field", "group"
|
|
63
|
+
options: {
|
|
64
|
+
variation: { type: "string", short: "v" },
|
|
65
|
+
label: { type: "string", short: "l" },
|
|
66
|
+
"non-repeatable": { type: "boolean" },
|
|
67
|
+
types: { type: "string" },
|
|
68
|
+
help: { type: "boolean", short: "h" },
|
|
69
|
+
},
|
|
70
|
+
allowPositionals: true,
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
if (help) {
|
|
74
|
+
console.info(HELP);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (!sliceId) {
|
|
79
|
+
console.error("Missing required argument: slice-id\n");
|
|
80
|
+
console.error("Usage: prismic slice add-field group <slice-id> <field-id>");
|
|
81
|
+
process.exitCode = 1;
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (!fieldId) {
|
|
86
|
+
console.error("Missing required argument: field-id\n");
|
|
87
|
+
console.error("Usage: prismic slice add-field group <slice-id> <field-id>");
|
|
88
|
+
process.exitCode = 1;
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// Groups cannot be nested
|
|
93
|
+
if (fieldId.includes(".")) {
|
|
94
|
+
console.error("Groups cannot be nested inside other groups");
|
|
95
|
+
process.exitCode = 1;
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Find the slice model
|
|
100
|
+
const result = await findSliceModel(sliceId);
|
|
101
|
+
if (!result.ok) {
|
|
102
|
+
console.error(result.error);
|
|
103
|
+
process.exitCode = 1;
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const { model, modelPath } = result;
|
|
108
|
+
|
|
109
|
+
// Check for variations
|
|
110
|
+
if (model.variations.length === 0) {
|
|
111
|
+
console.error(`Slice "${sliceId}" has no variations.\n`);
|
|
112
|
+
console.error("Add a variation first before adding fields.");
|
|
113
|
+
process.exitCode = 1;
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Find target variation
|
|
118
|
+
const targetVariation = variation
|
|
119
|
+
? model.variations.find((v) => v.id === variation)
|
|
120
|
+
: model.variations[0];
|
|
121
|
+
|
|
122
|
+
if (!targetVariation) {
|
|
123
|
+
console.error(`Variation "${variation}" not found in slice "${sliceId}"\n`);
|
|
124
|
+
console.error(`Available variations: ${model.variations.map((v) => v.id).join(", ")}`);
|
|
125
|
+
process.exitCode = 1;
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Initialize primary if it doesn't exist
|
|
130
|
+
if (!targetVariation.primary) {
|
|
131
|
+
targetVariation.primary = {};
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Check if field already exists in any variation
|
|
135
|
+
for (const v of model.variations) {
|
|
136
|
+
if (v.primary?.[fieldId]) {
|
|
137
|
+
console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
|
|
138
|
+
process.exitCode = 1;
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Build field definition
|
|
144
|
+
const fieldDefinition: Group = {
|
|
145
|
+
type: "Group",
|
|
146
|
+
config: {
|
|
147
|
+
label: label ?? humanReadable(fieldId),
|
|
148
|
+
repeat: !nonRepeatable,
|
|
149
|
+
fields: {},
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
// Add field to variation
|
|
154
|
+
targetVariation.primary[fieldId] = fieldDefinition;
|
|
155
|
+
|
|
156
|
+
// Write updated model
|
|
157
|
+
try {
|
|
158
|
+
await writeFile(modelPath, stringify(model as SharedSlice));
|
|
159
|
+
} catch (error) {
|
|
160
|
+
if (error instanceof Error) {
|
|
161
|
+
console.error(`Failed to update slice: ${error.message}`);
|
|
162
|
+
} else {
|
|
163
|
+
console.error("Failed to update slice");
|
|
164
|
+
}
|
|
165
|
+
process.exitCode = 1;
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
console.info(
|
|
170
|
+
`Added field "${fieldId}" (Group) to "${targetVariation.id}" variation in ${sliceId}`,
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
try {
|
|
174
|
+
await buildTypes({ output: types });
|
|
175
|
+
console.info(`Updated types in ${types ?? "prismicio-types.d.ts"}`);
|
|
176
|
+
} catch (error) {
|
|
177
|
+
console.warn(`Could not generate types: ${error instanceof Error ? error.message : error}`);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
console.info();
|
|
181
|
+
console.info(`Next: Add fields to the group with \`prismic slice add-field <type> ${sliceId} ${fieldId}.<field-id>\``);
|
|
182
|
+
|
|
183
|
+
const frameworkInfo = await detectFrameworkInfo();
|
|
184
|
+
if (frameworkInfo?.framework) {
|
|
185
|
+
const docsPath = getDocsPath(frameworkInfo.framework);
|
|
186
|
+
const anchor = getWriteComponentsAnchor(frameworkInfo.framework);
|
|
187
|
+
console.info(
|
|
188
|
+
` Run \`prismic docs fetch ${docsPath}${anchor}\` to learn how to implement the slice's component`,
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
@@ -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";
|
|
@@ -87,6 +88,15 @@ export async function sliceAddFieldImage(): Promise<void> {
|
|
|
87
88
|
return;
|
|
88
89
|
}
|
|
89
90
|
|
|
91
|
+
// Parse and validate field path
|
|
92
|
+
const fieldPath = parseFieldPath(fieldId);
|
|
93
|
+
const pathValidation = validateNestedFieldPath(fieldPath);
|
|
94
|
+
if (!pathValidation.ok) {
|
|
95
|
+
console.error(pathValidation.error);
|
|
96
|
+
process.exitCode = 1;
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
90
100
|
// Find the slice model
|
|
91
101
|
const result = await findSliceModel(sliceId);
|
|
92
102
|
if (!result.ok) {
|
|
@@ -122,25 +132,52 @@ export async function sliceAddFieldImage(): Promise<void> {
|
|
|
122
132
|
targetVariation.primary = {};
|
|
123
133
|
}
|
|
124
134
|
|
|
125
|
-
// Check if field already exists in any variation
|
|
126
|
-
for (const v of model.variations) {
|
|
127
|
-
if (v.primary?.[fieldId]) {
|
|
128
|
-
console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
|
|
129
|
-
process.exitCode = 1;
|
|
130
|
-
return;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
135
|
// Build field definition
|
|
135
136
|
const fieldDefinition: Image = {
|
|
136
137
|
type: "Image",
|
|
137
138
|
config: {
|
|
138
|
-
label: label ?? humanReadable(fieldId),
|
|
139
|
+
label: label ?? humanReadable(fieldPath.type === "nested" ? fieldPath.nestedFieldId : fieldId),
|
|
139
140
|
},
|
|
140
141
|
};
|
|
141
142
|
|
|
142
|
-
// Add field to variation
|
|
143
|
-
|
|
143
|
+
// Add field to variation (with nested field support)
|
|
144
|
+
if (fieldPath.type === "nested") {
|
|
145
|
+
const groupResult = findGroupInVariation(targetVariation.primary, fieldPath.groupId, targetVariation.id);
|
|
146
|
+
if (!groupResult.ok) {
|
|
147
|
+
console.error(groupResult.error);
|
|
148
|
+
process.exitCode = 1;
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
// Check if nested field already exists
|
|
152
|
+
if (groupResult.group.config.fields[fieldPath.nestedFieldId]) {
|
|
153
|
+
console.error(
|
|
154
|
+
`Field "${fieldPath.nestedFieldId}" already exists in group "${fieldPath.groupId}"`,
|
|
155
|
+
);
|
|
156
|
+
process.exitCode = 1;
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
groupResult.group.config.fields[fieldPath.nestedFieldId] = fieldDefinition;
|
|
160
|
+
} else {
|
|
161
|
+
// Check if field already exists in any variation (at top level or in groups)
|
|
162
|
+
for (const v of model.variations) {
|
|
163
|
+
if (v.primary?.[fieldId]) {
|
|
164
|
+
console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
|
|
165
|
+
process.exitCode = 1;
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
// Also check inside groups
|
|
169
|
+
for (const [groupFieldId, groupField] of Object.entries(v.primary ?? {})) {
|
|
170
|
+
if (isGroupField(groupField) && groupField.config.fields[fieldId]) {
|
|
171
|
+
console.error(
|
|
172
|
+
`Field "${fieldId}" already exists in group "${groupFieldId}" in variation "${v.id}"`,
|
|
173
|
+
);
|
|
174
|
+
process.exitCode = 1;
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
targetVariation.primary[fieldId] = fieldDefinition;
|
|
180
|
+
}
|
|
144
181
|
|
|
145
182
|
// Write updated model
|
|
146
183
|
try {
|
|
@@ -155,9 +192,15 @@ export async function sliceAddFieldImage(): Promise<void> {
|
|
|
155
192
|
return;
|
|
156
193
|
}
|
|
157
194
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
195
|
+
if (fieldPath.type === "nested") {
|
|
196
|
+
console.info(
|
|
197
|
+
`Added field "${fieldPath.nestedFieldId}" (Image) to group "${fieldPath.groupId}" in ${sliceId}`,
|
|
198
|
+
);
|
|
199
|
+
} else {
|
|
200
|
+
console.info(
|
|
201
|
+
`Added field "${fieldId}" (Image) to "${targetVariation.id}" variation in ${sliceId}`,
|
|
202
|
+
);
|
|
203
|
+
}
|
|
161
204
|
|
|
162
205
|
try {
|
|
163
206
|
await buildTypes({ output: types });
|
|
@@ -174,7 +217,7 @@ export async function sliceAddFieldImage(): Promise<void> {
|
|
|
174
217
|
const docsPath = getDocsPath(frameworkInfo.framework);
|
|
175
218
|
const anchor = getWriteComponentsAnchor(frameworkInfo.framework);
|
|
176
219
|
console.info(
|
|
177
|
-
` Run \`prismic docs ${docsPath}${anchor}\` to learn how to implement the slice's component`,
|
|
220
|
+
` Run \`prismic docs fetch ${docsPath}${anchor}\` to learn how to implement the slice's component`,
|
|
178
221
|
);
|
|
179
222
|
}
|
|
180
223
|
}
|
|
@@ -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 sliceAddFieldKeyText(): 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 sliceAddFieldKeyText(): 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: Text = {
|
|
138
139
|
type: "Text",
|
|
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
|
-
|
|
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 sliceAddFieldKeyText(): Promise<void> {
|
|
|
158
195
|
return;
|
|
159
196
|
}
|
|
160
197
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
198
|
+
if (fieldPath.type === "nested") {
|
|
199
|
+
console.info(
|
|
200
|
+
`Added field "${fieldPath.nestedFieldId}" (Text) to group "${fieldPath.groupId}" in ${sliceId}`,
|
|
201
|
+
);
|
|
202
|
+
} else {
|
|
203
|
+
console.info(
|
|
204
|
+
`Added field "${fieldId}" (Text) 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 sliceAddFieldKeyText(): 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
|
}
|