@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
|
@@ -4,6 +4,8 @@ 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";
|
|
8
|
+
import { type Framework, detectFrameworkInfo } from "./lib/framework";
|
|
7
9
|
import { stringify } from "./lib/json";
|
|
8
10
|
import { findSliceModel } from "./lib/slice";
|
|
9
11
|
import { humanReadable } from "./lib/string";
|
|
@@ -31,6 +33,28 @@ EXAMPLES
|
|
|
31
33
|
prismic slice add-field date promo end_date --variation "countdown"
|
|
32
34
|
`.trim();
|
|
33
35
|
|
|
36
|
+
function getDocsPath(framework: Framework): string {
|
|
37
|
+
switch (framework) {
|
|
38
|
+
case "next":
|
|
39
|
+
return "nextjs/with-cli";
|
|
40
|
+
case "nuxt":
|
|
41
|
+
return "nuxt/with-cli";
|
|
42
|
+
case "sveltekit":
|
|
43
|
+
return "sveltekit/with-cli";
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function getWriteComponentsAnchor(framework: Framework): string {
|
|
48
|
+
switch (framework) {
|
|
49
|
+
case "nuxt":
|
|
50
|
+
return "#write-vue-components";
|
|
51
|
+
case "sveltekit":
|
|
52
|
+
return "#write-svelte-components";
|
|
53
|
+
default:
|
|
54
|
+
return "#write-react-components";
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
34
58
|
export async function sliceAddFieldDate(): Promise<void> {
|
|
35
59
|
const {
|
|
36
60
|
values: { help, variation, label, placeholder, types },
|
|
@@ -66,6 +90,15 @@ export async function sliceAddFieldDate(): Promise<void> {
|
|
|
66
90
|
return;
|
|
67
91
|
}
|
|
68
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
|
+
|
|
69
102
|
// Find the slice model
|
|
70
103
|
const result = await findSliceModel(sliceId);
|
|
71
104
|
if (!result.ok) {
|
|
@@ -101,26 +134,53 @@ export async function sliceAddFieldDate(): Promise<void> {
|
|
|
101
134
|
targetVariation.primary = {};
|
|
102
135
|
}
|
|
103
136
|
|
|
104
|
-
// Check if field already exists in any variation
|
|
105
|
-
for (const v of model.variations) {
|
|
106
|
-
if (v.primary?.[fieldId]) {
|
|
107
|
-
console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
|
|
108
|
-
process.exitCode = 1;
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
137
|
// Build field definition
|
|
114
138
|
const fieldDefinition: DateField = {
|
|
115
139
|
type: "Date",
|
|
116
140
|
config: {
|
|
117
|
-
label: label ?? humanReadable(fieldId),
|
|
141
|
+
label: label ?? humanReadable(fieldPath.type === "nested" ? fieldPath.nestedFieldId : fieldId),
|
|
118
142
|
...(placeholder && { placeholder }),
|
|
119
143
|
},
|
|
120
144
|
};
|
|
121
145
|
|
|
122
|
-
// Add field to variation
|
|
123
|
-
|
|
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
|
+
}
|
|
124
184
|
|
|
125
185
|
// Write updated model
|
|
126
186
|
try {
|
|
@@ -135,9 +195,15 @@ export async function sliceAddFieldDate(): Promise<void> {
|
|
|
135
195
|
return;
|
|
136
196
|
}
|
|
137
197
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
198
|
+
if (fieldPath.type === "nested") {
|
|
199
|
+
console.info(
|
|
200
|
+
`Added field "${fieldPath.nestedFieldId}" (Date) to group "${fieldPath.groupId}" in ${sliceId}`,
|
|
201
|
+
);
|
|
202
|
+
} else {
|
|
203
|
+
console.info(
|
|
204
|
+
`Added field "${fieldId}" (Date) to "${targetVariation.id}" variation in ${sliceId}`,
|
|
205
|
+
);
|
|
206
|
+
}
|
|
141
207
|
|
|
142
208
|
try {
|
|
143
209
|
await buildTypes({ output: types });
|
|
@@ -148,5 +214,13 @@ export async function sliceAddFieldDate(): Promise<void> {
|
|
|
148
214
|
|
|
149
215
|
console.info();
|
|
150
216
|
console.info("Next: Add more fields with `prismic slice add-field`");
|
|
151
|
-
|
|
217
|
+
|
|
218
|
+
const frameworkInfo = await detectFrameworkInfo();
|
|
219
|
+
if (frameworkInfo?.framework) {
|
|
220
|
+
const docsPath = getDocsPath(frameworkInfo.framework);
|
|
221
|
+
const anchor = getWriteComponentsAnchor(frameworkInfo.framework);
|
|
222
|
+
console.info(
|
|
223
|
+
` Run \`prismic docs ${docsPath}${anchor}\` to learn how to implement the slice's component`,
|
|
224
|
+
);
|
|
225
|
+
}
|
|
152
226
|
}
|
|
@@ -4,6 +4,8 @@ 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";
|
|
8
|
+
import { type Framework, detectFrameworkInfo } from "./lib/framework";
|
|
7
9
|
import { stringify } from "./lib/json";
|
|
8
10
|
import { findSliceModel } from "./lib/slice";
|
|
9
11
|
import { humanReadable } from "./lib/string";
|
|
@@ -31,6 +33,28 @@ EXAMPLES
|
|
|
31
33
|
prismic slice add-field embed social tweet --variation "twitter"
|
|
32
34
|
`.trim();
|
|
33
35
|
|
|
36
|
+
function getDocsPath(framework: Framework): string {
|
|
37
|
+
switch (framework) {
|
|
38
|
+
case "next":
|
|
39
|
+
return "nextjs/with-cli";
|
|
40
|
+
case "nuxt":
|
|
41
|
+
return "nuxt/with-cli";
|
|
42
|
+
case "sveltekit":
|
|
43
|
+
return "sveltekit/with-cli";
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function getWriteComponentsAnchor(framework: Framework): string {
|
|
48
|
+
switch (framework) {
|
|
49
|
+
case "nuxt":
|
|
50
|
+
return "#write-vue-components";
|
|
51
|
+
case "sveltekit":
|
|
52
|
+
return "#write-svelte-components";
|
|
53
|
+
default:
|
|
54
|
+
return "#write-react-components";
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
34
58
|
export async function sliceAddFieldEmbed(): Promise<void> {
|
|
35
59
|
const {
|
|
36
60
|
values: { help, variation, label, placeholder, types },
|
|
@@ -66,6 +90,15 @@ export async function sliceAddFieldEmbed(): Promise<void> {
|
|
|
66
90
|
return;
|
|
67
91
|
}
|
|
68
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
|
+
|
|
69
102
|
// Find the slice model
|
|
70
103
|
const result = await findSliceModel(sliceId);
|
|
71
104
|
if (!result.ok) {
|
|
@@ -101,26 +134,53 @@ export async function sliceAddFieldEmbed(): Promise<void> {
|
|
|
101
134
|
targetVariation.primary = {};
|
|
102
135
|
}
|
|
103
136
|
|
|
104
|
-
// Check if field already exists in any variation
|
|
105
|
-
for (const v of model.variations) {
|
|
106
|
-
if (v.primary?.[fieldId]) {
|
|
107
|
-
console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
|
|
108
|
-
process.exitCode = 1;
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
137
|
// Build field definition
|
|
114
138
|
const fieldDefinition: Embed = {
|
|
115
139
|
type: "Embed",
|
|
116
140
|
config: {
|
|
117
|
-
label: label ?? humanReadable(fieldId),
|
|
141
|
+
label: label ?? humanReadable(fieldPath.type === "nested" ? fieldPath.nestedFieldId : fieldId),
|
|
118
142
|
...(placeholder && { placeholder }),
|
|
119
143
|
},
|
|
120
144
|
};
|
|
121
145
|
|
|
122
|
-
// Add field to variation
|
|
123
|
-
|
|
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
|
+
}
|
|
124
184
|
|
|
125
185
|
// Write updated model
|
|
126
186
|
try {
|
|
@@ -135,9 +195,15 @@ export async function sliceAddFieldEmbed(): Promise<void> {
|
|
|
135
195
|
return;
|
|
136
196
|
}
|
|
137
197
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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
|
+
}
|
|
141
207
|
|
|
142
208
|
try {
|
|
143
209
|
await buildTypes({ output: types });
|
|
@@ -148,5 +214,13 @@ export async function sliceAddFieldEmbed(): Promise<void> {
|
|
|
148
214
|
|
|
149
215
|
console.info();
|
|
150
216
|
console.info("Next: Add more fields with `prismic slice add-field`");
|
|
151
|
-
|
|
217
|
+
|
|
218
|
+
const frameworkInfo = await detectFrameworkInfo();
|
|
219
|
+
if (frameworkInfo?.framework) {
|
|
220
|
+
const docsPath = getDocsPath(frameworkInfo.framework);
|
|
221
|
+
const anchor = getWriteComponentsAnchor(frameworkInfo.framework);
|
|
222
|
+
console.info(
|
|
223
|
+
` Run \`prismic docs ${docsPath}${anchor}\` to learn how to implement the slice's component`,
|
|
224
|
+
);
|
|
225
|
+
}
|
|
152
226
|
}
|
|
@@ -4,6 +4,8 @@ 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";
|
|
8
|
+
import { type Framework, detectFrameworkInfo } from "./lib/framework";
|
|
7
9
|
import { stringify } from "./lib/json";
|
|
8
10
|
import { findSliceModel } from "./lib/slice";
|
|
9
11
|
import { humanReadable } from "./lib/string";
|
|
@@ -30,6 +32,28 @@ EXAMPLES
|
|
|
30
32
|
prismic slice add-field geo-point map marker --variation "interactive"
|
|
31
33
|
`.trim();
|
|
32
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
|
+
|
|
33
57
|
export async function sliceAddFieldGeoPoint(): Promise<void> {
|
|
34
58
|
const {
|
|
35
59
|
values: { help, variation, label, types },
|
|
@@ -64,6 +88,15 @@ export async function sliceAddFieldGeoPoint(): Promise<void> {
|
|
|
64
88
|
return;
|
|
65
89
|
}
|
|
66
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
|
+
|
|
67
100
|
// Find the slice model
|
|
68
101
|
const result = await findSliceModel(sliceId);
|
|
69
102
|
if (!result.ok) {
|
|
@@ -99,25 +132,52 @@ export async function sliceAddFieldGeoPoint(): Promise<void> {
|
|
|
99
132
|
targetVariation.primary = {};
|
|
100
133
|
}
|
|
101
134
|
|
|
102
|
-
// Check if field already exists in any variation
|
|
103
|
-
for (const v of model.variations) {
|
|
104
|
-
if (v.primary?.[fieldId]) {
|
|
105
|
-
console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
|
|
106
|
-
process.exitCode = 1;
|
|
107
|
-
return;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
135
|
// Build field definition
|
|
112
136
|
const fieldDefinition: GeoPoint = {
|
|
113
137
|
type: "GeoPoint",
|
|
114
138
|
config: {
|
|
115
|
-
label: label ?? humanReadable(fieldId),
|
|
139
|
+
label: label ?? humanReadable(fieldPath.type === "nested" ? fieldPath.nestedFieldId : fieldId),
|
|
116
140
|
},
|
|
117
141
|
};
|
|
118
142
|
|
|
119
|
-
// Add field to variation
|
|
120
|
-
|
|
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
|
+
}
|
|
121
181
|
|
|
122
182
|
// Write updated model
|
|
123
183
|
try {
|
|
@@ -132,9 +192,15 @@ export async function sliceAddFieldGeoPoint(): Promise<void> {
|
|
|
132
192
|
return;
|
|
133
193
|
}
|
|
134
194
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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
|
+
}
|
|
138
204
|
|
|
139
205
|
try {
|
|
140
206
|
await buildTypes({ output: types });
|
|
@@ -145,5 +211,13 @@ export async function sliceAddFieldGeoPoint(): Promise<void> {
|
|
|
145
211
|
|
|
146
212
|
console.info();
|
|
147
213
|
console.info("Next: Add more fields with `prismic slice add-field`");
|
|
148
|
-
|
|
214
|
+
|
|
215
|
+
const frameworkInfo = await detectFrameworkInfo();
|
|
216
|
+
if (frameworkInfo?.framework) {
|
|
217
|
+
const docsPath = getDocsPath(frameworkInfo.framework);
|
|
218
|
+
const anchor = getWriteComponentsAnchor(frameworkInfo.framework);
|
|
219
|
+
console.info(
|
|
220
|
+
` Run \`prismic docs ${docsPath}${anchor}\` to learn how to implement the slice's component`,
|
|
221
|
+
);
|
|
222
|
+
}
|
|
149
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 ${docsPath}${anchor}\` to learn how to implement the slice's component`,
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
}
|