@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";
|
|
@@ -30,6 +32,28 @@ EXAMPLES
|
|
|
30
32
|
prismic slice add-field image gallery thumbnail --variation "grid"
|
|
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 sliceAddFieldImage(): Promise<void> {
|
|
34
58
|
const {
|
|
35
59
|
values: { help, variation, label, types },
|
|
@@ -64,6 +88,15 @@ export async function sliceAddFieldImage(): 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 sliceAddFieldImage(): 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: Image = {
|
|
113
137
|
type: "Image",
|
|
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 sliceAddFieldImage(): 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}" (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
|
+
}
|
|
138
204
|
|
|
139
205
|
try {
|
|
140
206
|
await buildTypes({ output: types });
|
|
@@ -145,5 +211,13 @@ export async function sliceAddFieldImage(): 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
|
}
|
|
@@ -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 key-text cta button_text --placeholder "Enter button text"
|
|
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 sliceAddFieldKeyText(): Promise<void> {
|
|
35
59
|
const {
|
|
36
60
|
values: { help, variation, label, placeholder, types },
|
|
@@ -66,6 +90,15 @@ export async function sliceAddFieldKeyText(): 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 sliceAddFieldKeyText(): 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: Text = {
|
|
115
139
|
type: "Text",
|
|
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 sliceAddFieldKeyText(): 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}" (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
|
+
}
|
|
141
207
|
|
|
142
208
|
try {
|
|
143
209
|
await buildTypes({ output: types });
|
|
@@ -148,5 +214,13 @@ export async function sliceAddFieldKeyText(): 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";
|
|
@@ -35,6 +37,28 @@ EXAMPLES
|
|
|
35
37
|
prismic slice add-field link hero cta --allow-text --allow-target-blank
|
|
36
38
|
`.trim();
|
|
37
39
|
|
|
40
|
+
function getDocsPath(framework: Framework): string {
|
|
41
|
+
switch (framework) {
|
|
42
|
+
case "next":
|
|
43
|
+
return "nextjs/with-cli";
|
|
44
|
+
case "nuxt":
|
|
45
|
+
return "nuxt/with-cli";
|
|
46
|
+
case "sveltekit":
|
|
47
|
+
return "sveltekit/with-cli";
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function getWriteComponentsAnchor(framework: Framework): string {
|
|
52
|
+
switch (framework) {
|
|
53
|
+
case "nuxt":
|
|
54
|
+
return "#write-vue-components";
|
|
55
|
+
case "sveltekit":
|
|
56
|
+
return "#write-svelte-components";
|
|
57
|
+
default:
|
|
58
|
+
return "#write-react-components";
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
38
62
|
export async function sliceAddFieldLink(): Promise<void> {
|
|
39
63
|
const {
|
|
40
64
|
values: {
|
|
@@ -82,6 +106,15 @@ export async function sliceAddFieldLink(): Promise<void> {
|
|
|
82
106
|
return;
|
|
83
107
|
}
|
|
84
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
|
+
|
|
85
118
|
// Find the slice model
|
|
86
119
|
const result = await findSliceModel(sliceId);
|
|
87
120
|
if (!result.ok) {
|
|
@@ -117,20 +150,11 @@ export async function sliceAddFieldLink(): Promise<void> {
|
|
|
117
150
|
targetVariation.primary = {};
|
|
118
151
|
}
|
|
119
152
|
|
|
120
|
-
// Check if field already exists in any variation
|
|
121
|
-
for (const v of model.variations) {
|
|
122
|
-
if (v.primary?.[fieldId]) {
|
|
123
|
-
console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
|
|
124
|
-
process.exitCode = 1;
|
|
125
|
-
return;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
|
|
129
153
|
// Build field definition
|
|
130
154
|
const fieldDefinition: Link = {
|
|
131
155
|
type: "Link",
|
|
132
156
|
config: {
|
|
133
|
-
label: label ?? humanReadable(fieldId),
|
|
157
|
+
label: label ?? humanReadable(fieldPath.type === "nested" ? fieldPath.nestedFieldId : fieldId),
|
|
134
158
|
...(placeholder && { placeholder }),
|
|
135
159
|
...(allowText && { allowText: true }),
|
|
136
160
|
...(allowTargetBlank && { allowTargetBlank: true }),
|
|
@@ -138,8 +162,44 @@ export async function sliceAddFieldLink(): Promise<void> {
|
|
|
138
162
|
},
|
|
139
163
|
};
|
|
140
164
|
|
|
141
|
-
// Add field to variation
|
|
142
|
-
|
|
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
|
+
}
|
|
143
203
|
|
|
144
204
|
// Write updated model
|
|
145
205
|
try {
|
|
@@ -154,9 +214,15 @@ export async function sliceAddFieldLink(): Promise<void> {
|
|
|
154
214
|
return;
|
|
155
215
|
}
|
|
156
216
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
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
|
+
}
|
|
160
226
|
|
|
161
227
|
try {
|
|
162
228
|
await buildTypes({ output: types });
|
|
@@ -167,5 +233,13 @@ export async function sliceAddFieldLink(): Promise<void> {
|
|
|
167
233
|
|
|
168
234
|
console.info();
|
|
169
235
|
console.info("Next: Add more fields with `prismic slice add-field`");
|
|
170
|
-
|
|
236
|
+
|
|
237
|
+
const frameworkInfo = await detectFrameworkInfo();
|
|
238
|
+
if (frameworkInfo?.framework) {
|
|
239
|
+
const docsPath = getDocsPath(frameworkInfo.framework);
|
|
240
|
+
const anchor = getWriteComponentsAnchor(frameworkInfo.framework);
|
|
241
|
+
console.info(
|
|
242
|
+
` Run \`prismic docs ${docsPath}${anchor}\` to learn how to implement the slice's component`,
|
|
243
|
+
);
|
|
244
|
+
}
|
|
171
245
|
}
|
|
@@ -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 number stats count --variation "detailed"
|
|
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 sliceAddFieldNumber(): Promise<void> {
|
|
35
59
|
const {
|
|
36
60
|
values: { help, variation, label, placeholder, types },
|
|
@@ -66,6 +90,15 @@ export async function sliceAddFieldNumber(): 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 sliceAddFieldNumber(): 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: Number = {
|
|
115
139
|
type: "Number",
|
|
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 sliceAddFieldNumber(): 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}" (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
|
+
}
|
|
141
207
|
|
|
142
208
|
try {
|
|
143
209
|
await buildTypes({ output: types });
|
|
@@ -148,5 +214,13 @@ export async function sliceAddFieldNumber(): 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
|
}
|