prismic 0.0.0-pr.28.59bf330

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 (158) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +69 -0
  3. package/dist/builders-hKD4IrLX-DsO7BUQw.mjs +97 -0
  4. package/dist/dist-B11B2hHn.mjs +1 -0
  5. package/dist/dist-DT8CtumB.mjs +1 -0
  6. package/dist/framework-CfjEoVk0.mjs +17 -0
  7. package/dist/index.mjs +2537 -0
  8. package/dist/nextjs-9z7YrSnS.mjs +312 -0
  9. package/dist/nuxt-KoJ61G2q.mjs +59 -0
  10. package/dist/sveltekit-DjXKCG78.mjs +226 -0
  11. package/package.json +58 -0
  12. package/src/codegen-types.ts +82 -0
  13. package/src/codegen.ts +45 -0
  14. package/src/custom-type-add-field-boolean.ts +185 -0
  15. package/src/custom-type-add-field-color.ts +168 -0
  16. package/src/custom-type-add-field-date.ts +171 -0
  17. package/src/custom-type-add-field-embed.ts +168 -0
  18. package/src/custom-type-add-field-geo-point.ts +165 -0
  19. package/src/custom-type-add-field-group.ts +142 -0
  20. package/src/custom-type-add-field-image.ts +168 -0
  21. package/src/custom-type-add-field-key-text.ts +168 -0
  22. package/src/custom-type-add-field-link.ts +191 -0
  23. package/src/custom-type-add-field-number.ts +200 -0
  24. package/src/custom-type-add-field-rich-text.ts +192 -0
  25. package/src/custom-type-add-field-select.ts +174 -0
  26. package/src/custom-type-add-field-timestamp.ts +171 -0
  27. package/src/custom-type-add-field-uid.ts +151 -0
  28. package/src/custom-type-add-field.ts +116 -0
  29. package/src/custom-type-connect-slice.ts +178 -0
  30. package/src/custom-type-create.ts +98 -0
  31. package/src/custom-type-disconnect-slice.ts +134 -0
  32. package/src/custom-type-list.ts +110 -0
  33. package/src/custom-type-remove-field.ts +135 -0
  34. package/src/custom-type-remove.ts +103 -0
  35. package/src/custom-type-set-name.ts +102 -0
  36. package/src/custom-type-view.ts +118 -0
  37. package/src/custom-type.ts +85 -0
  38. package/src/docs-fetch.ts +146 -0
  39. package/src/docs-list.ts +131 -0
  40. package/src/docs.ts +54 -0
  41. package/src/env.d.ts +12 -0
  42. package/src/framework/index.ts +399 -0
  43. package/src/framework/nextjs.templates.ts +426 -0
  44. package/src/framework/nextjs.ts +216 -0
  45. package/src/framework/nuxt.templates.ts +74 -0
  46. package/src/framework/nuxt.ts +250 -0
  47. package/src/framework/sveltekit.templates.ts +278 -0
  48. package/src/framework/sveltekit.ts +241 -0
  49. package/src/index.ts +155 -0
  50. package/src/init.ts +173 -0
  51. package/src/lib/auth.ts +200 -0
  52. package/src/lib/browser.ts +11 -0
  53. package/src/lib/config.ts +111 -0
  54. package/src/lib/custom-types-api.ts +385 -0
  55. package/src/lib/field-path.ts +81 -0
  56. package/src/lib/file.ts +49 -0
  57. package/src/lib/json.ts +3 -0
  58. package/src/lib/packageJson.ts +35 -0
  59. package/src/lib/profile.ts +39 -0
  60. package/src/lib/request.ts +116 -0
  61. package/src/lib/segment.ts +145 -0
  62. package/src/lib/sentry.ts +63 -0
  63. package/src/lib/string.ts +10 -0
  64. package/src/lib/url.ts +31 -0
  65. package/src/locale-add.ts +116 -0
  66. package/src/locale-list.ts +107 -0
  67. package/src/locale-remove.ts +88 -0
  68. package/src/locale-set-default.ts +131 -0
  69. package/src/locale.ts +60 -0
  70. package/src/login.ts +45 -0
  71. package/src/logout.ts +36 -0
  72. package/src/page-type-add-field-boolean.ts +179 -0
  73. package/src/page-type-add-field-color.ts +165 -0
  74. package/src/page-type-add-field-date.ts +168 -0
  75. package/src/page-type-add-field-embed.ts +165 -0
  76. package/src/page-type-add-field-geo-point.ts +162 -0
  77. package/src/page-type-add-field-group.ts +139 -0
  78. package/src/page-type-add-field-image.ts +165 -0
  79. package/src/page-type-add-field-key-text.ts +165 -0
  80. package/src/page-type-add-field-link.ts +188 -0
  81. package/src/page-type-add-field-number.ts +197 -0
  82. package/src/page-type-add-field-rich-text.ts +189 -0
  83. package/src/page-type-add-field-select.ts +171 -0
  84. package/src/page-type-add-field-timestamp.ts +168 -0
  85. package/src/page-type-add-field-uid.ts +148 -0
  86. package/src/page-type-add-field.ts +116 -0
  87. package/src/page-type-connect-slice.ts +178 -0
  88. package/src/page-type-create.ts +128 -0
  89. package/src/page-type-disconnect-slice.ts +134 -0
  90. package/src/page-type-list.ts +109 -0
  91. package/src/page-type-remove-field.ts +135 -0
  92. package/src/page-type-remove.ts +103 -0
  93. package/src/page-type-set-name.ts +102 -0
  94. package/src/page-type-set-repeatable.ts +111 -0
  95. package/src/page-type-view.ts +118 -0
  96. package/src/page-type.ts +90 -0
  97. package/src/preview-add.ts +126 -0
  98. package/src/preview-get-simulator.ts +104 -0
  99. package/src/preview-list.ts +106 -0
  100. package/src/preview-remove-simulator.ts +80 -0
  101. package/src/preview-remove.ts +109 -0
  102. package/src/preview-set-name.ts +137 -0
  103. package/src/preview-set-simulator.ts +116 -0
  104. package/src/preview.ts +75 -0
  105. package/src/pull.ts +236 -0
  106. package/src/push.ts +409 -0
  107. package/src/repo-create.ts +175 -0
  108. package/src/repo-get-access.ts +86 -0
  109. package/src/repo-list.ts +100 -0
  110. package/src/repo-set-access.ts +100 -0
  111. package/src/repo-set-name.ts +102 -0
  112. package/src/repo-view.ts +113 -0
  113. package/src/repo.ts +70 -0
  114. package/src/slice-add-field-boolean.ts +219 -0
  115. package/src/slice-add-field-color.ts +205 -0
  116. package/src/slice-add-field-date.ts +205 -0
  117. package/src/slice-add-field-embed.ts +205 -0
  118. package/src/slice-add-field-geo-point.ts +202 -0
  119. package/src/slice-add-field-group.ts +170 -0
  120. package/src/slice-add-field-image.ts +202 -0
  121. package/src/slice-add-field-key-text.ts +205 -0
  122. package/src/slice-add-field-link.ts +224 -0
  123. package/src/slice-add-field-number.ts +205 -0
  124. package/src/slice-add-field-rich-text.ts +229 -0
  125. package/src/slice-add-field-select.ts +211 -0
  126. package/src/slice-add-field-timestamp.ts +205 -0
  127. package/src/slice-add-field.ts +111 -0
  128. package/src/slice-add-variation.ts +142 -0
  129. package/src/slice-create.ts +164 -0
  130. package/src/slice-list-variations.ts +71 -0
  131. package/src/slice-list.ts +60 -0
  132. package/src/slice-remove-field.ts +125 -0
  133. package/src/slice-remove-variation.ts +113 -0
  134. package/src/slice-remove.ts +92 -0
  135. package/src/slice-rename.ts +104 -0
  136. package/src/slice-set-screenshot.ts +239 -0
  137. package/src/slice-view.ts +83 -0
  138. package/src/slice.ts +95 -0
  139. package/src/status.ts +834 -0
  140. package/src/sync.ts +259 -0
  141. package/src/token-create.ts +203 -0
  142. package/src/token-delete.ts +182 -0
  143. package/src/token-list.ts +223 -0
  144. package/src/token-set-name.ts +193 -0
  145. package/src/token.ts +60 -0
  146. package/src/webhook-add-header.ts +118 -0
  147. package/src/webhook-create.ts +152 -0
  148. package/src/webhook-disable.ts +109 -0
  149. package/src/webhook-enable.ts +132 -0
  150. package/src/webhook-list.ts +93 -0
  151. package/src/webhook-remove-header.ts +117 -0
  152. package/src/webhook-remove.ts +106 -0
  153. package/src/webhook-set-triggers.ts +148 -0
  154. package/src/webhook-status.ts +90 -0
  155. package/src/webhook-test.ts +106 -0
  156. package/src/webhook-view.ts +147 -0
  157. package/src/webhook.ts +95 -0
  158. package/src/whoami.ts +62 -0
@@ -0,0 +1,205 @@
1
+ import type { Number, SharedSlice } from "@prismicio/types-internal/lib/customtypes";
2
+
3
+ import { parseArgs } from "node:util";
4
+
5
+ import { buildTypes } from "./codegen-types";
6
+ import { findGroupInVariation, isGroupField, parseFieldPath, validateNestedFieldPath } from "./lib/field-path";
7
+ import { getDocsPath, getWriteComponentsAnchor, requireFramework } from "./framework";
8
+ import { humanReadable } from "./lib/string";
9
+
10
+ const HELP = `
11
+ Add a number field to an existing slice.
12
+
13
+ USAGE
14
+ prismic slice add-field number <slice-id> <field-id> [flags]
15
+
16
+ ARGUMENTS
17
+ slice-id Slice identifier (required)
18
+ field-id Field identifier (required)
19
+
20
+ FLAGS
21
+ -v, --variation string Target variation (default: first variation)
22
+ -l, --label string Display label for the field (inferred from field-id if omitted)
23
+ -p, --placeholder string Placeholder text
24
+ --types string Output file for generated types (default: "prismicio-types.d.ts")
25
+ -h, --help Show help for command
26
+
27
+ EXAMPLES
28
+ prismic slice add-field number my_slice price
29
+ prismic slice add-field number product quantity --label "Quantity"
30
+ prismic slice add-field number stats count --variation "detailed"
31
+ `.trim();
32
+
33
+
34
+
35
+ export async function sliceAddFieldNumber(): Promise<void> {
36
+ const {
37
+ values: { help, variation, label, placeholder, types },
38
+ positionals: [sliceId, fieldId],
39
+ } = parseArgs({
40
+ args: process.argv.slice(5), // skip: node, script, "slice", "add-field", "number"
41
+ options: {
42
+ variation: { type: "string", short: "v" },
43
+ label: { type: "string", short: "l" },
44
+ placeholder: { type: "string", short: "p" },
45
+ types: { type: "string" },
46
+ help: { type: "boolean", short: "h" },
47
+ },
48
+ allowPositionals: true,
49
+ });
50
+
51
+ if (help) {
52
+ console.info(HELP);
53
+ return;
54
+ }
55
+
56
+ if (!sliceId) {
57
+ console.error("Missing required argument: slice-id\n");
58
+ console.error("Usage: prismic slice add-field number <slice-id> <field-id>");
59
+ process.exitCode = 1;
60
+ return;
61
+ }
62
+
63
+ if (!fieldId) {
64
+ console.error("Missing required argument: field-id\n");
65
+ console.error("Usage: prismic slice add-field number <slice-id> <field-id>");
66
+ process.exitCode = 1;
67
+ return;
68
+ }
69
+
70
+ // Parse and validate field path
71
+ const fieldPath = parseFieldPath(fieldId);
72
+ const pathValidation = validateNestedFieldPath(fieldPath);
73
+ if (!pathValidation.ok) {
74
+ console.error(pathValidation.error);
75
+ process.exitCode = 1;
76
+ return;
77
+ }
78
+
79
+ // Find the slice model
80
+ const framework = await requireFramework();
81
+ if (!framework) return;
82
+
83
+ let model: SharedSlice;
84
+ try {
85
+ model = await framework.readSlice(sliceId);
86
+ } catch {
87
+ console.error(`Slice not found: ${sliceId}\n\nCreate it first with: prismic slice create ${sliceId}`);
88
+ process.exitCode = 1;
89
+ return;
90
+ }
91
+
92
+ // Check for variations
93
+ if (model.variations.length === 0) {
94
+ console.error(`Slice "${sliceId}" has no variations.\n`);
95
+ console.error("Add a variation first before adding fields.");
96
+ process.exitCode = 1;
97
+ return;
98
+ }
99
+
100
+ // Find target variation
101
+ const targetVariation = variation
102
+ ? model.variations.find((v) => v.id === variation)
103
+ : model.variations[0];
104
+
105
+ if (!targetVariation) {
106
+ console.error(`Variation "${variation}" not found in slice "${sliceId}"\n`);
107
+ console.error(`Available variations: ${model.variations.map((v) => v.id).join(", ")}`);
108
+ process.exitCode = 1;
109
+ return;
110
+ }
111
+
112
+ // Initialize primary if it doesn't exist
113
+ if (!targetVariation.primary) {
114
+ targetVariation.primary = {};
115
+ }
116
+
117
+ // Build field definition
118
+ const fieldDefinition: Number = {
119
+ type: "Number",
120
+ config: {
121
+ label: label ?? humanReadable(fieldPath.type === "nested" ? fieldPath.nestedFieldId : fieldId),
122
+ ...(placeholder && { placeholder }),
123
+ },
124
+ };
125
+
126
+ // Add field to variation (with nested field support)
127
+ if (fieldPath.type === "nested") {
128
+ const groupResult = findGroupInVariation(targetVariation.primary, fieldPath.groupId, targetVariation.id);
129
+ if (!groupResult.ok) {
130
+ console.error(groupResult.error);
131
+ process.exitCode = 1;
132
+ return;
133
+ }
134
+ // Check if nested field already exists
135
+ if (groupResult.group.config.fields[fieldPath.nestedFieldId]) {
136
+ console.error(
137
+ `Field "${fieldPath.nestedFieldId}" already exists in group "${fieldPath.groupId}"`,
138
+ );
139
+ process.exitCode = 1;
140
+ return;
141
+ }
142
+ groupResult.group.config.fields[fieldPath.nestedFieldId] = fieldDefinition;
143
+ } else {
144
+ // Check if field already exists in any variation (at top level or in groups)
145
+ for (const v of model.variations) {
146
+ if (v.primary?.[fieldId]) {
147
+ console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
148
+ process.exitCode = 1;
149
+ return;
150
+ }
151
+ // Also check inside groups
152
+ for (const [groupFieldId, groupField] of Object.entries(v.primary ?? {})) {
153
+ if (isGroupField(groupField) && groupField.config.fields[fieldId]) {
154
+ console.error(
155
+ `Field "${fieldId}" already exists in group "${groupFieldId}" in variation "${v.id}"`,
156
+ );
157
+ process.exitCode = 1;
158
+ return;
159
+ }
160
+ }
161
+ }
162
+ targetVariation.primary[fieldId] = fieldDefinition;
163
+ }
164
+
165
+ // Write updated model
166
+ try {
167
+ await framework.updateSlice(model);
168
+ } catch (error) {
169
+ if (error instanceof Error) {
170
+ console.error(`Failed to update slice: ${error.message}`);
171
+ } else {
172
+ console.error("Failed to update slice");
173
+ }
174
+ process.exitCode = 1;
175
+ return;
176
+ }
177
+
178
+ if (fieldPath.type === "nested") {
179
+ console.info(
180
+ `Added field "${fieldPath.nestedFieldId}" (Number) to group "${fieldPath.groupId}" in ${sliceId}`,
181
+ );
182
+ } else {
183
+ console.info(
184
+ `Added field "${fieldId}" (Number) to "${targetVariation.id}" variation in ${sliceId}`,
185
+ );
186
+ }
187
+
188
+ try {
189
+ await buildTypes({ output: types });
190
+ console.info(`Updated types in ${types ?? "prismicio-types.d.ts"}`);
191
+ } catch (error) {
192
+ console.warn(`Could not generate types: ${error instanceof Error ? error.message : error}`);
193
+ }
194
+
195
+ console.info();
196
+ console.info("Next: Add more fields with `prismic slice add-field`");
197
+
198
+ if (framework) {
199
+ const docsPath = getDocsPath(framework.id);
200
+ const anchor = getWriteComponentsAnchor(framework.id);
201
+ console.info(
202
+ ` Run \`prismic docs fetch ${docsPath}${anchor}\` to learn how to implement the slice's component`,
203
+ );
204
+ }
205
+ }
@@ -0,0 +1,229 @@
1
+ import type { RichText, SharedSlice } from "@prismicio/types-internal/lib/customtypes";
2
+
3
+ import { parseArgs } from "node:util";
4
+
5
+ import { buildTypes } from "./codegen-types";
6
+ import { findGroupInVariation, isGroupField, parseFieldPath, validateNestedFieldPath } from "./lib/field-path";
7
+ import { getDocsPath, getWriteComponentsAnchor, requireFramework } from "./framework";
8
+ import { humanReadable } from "./lib/string";
9
+
10
+ const HELP = `
11
+ Add a rich text field to an existing slice.
12
+
13
+ USAGE
14
+ prismic slice add-field rich-text <slice-id> <field-id> [flags]
15
+
16
+ ARGUMENTS
17
+ slice-id Slice identifier (required)
18
+ field-id Field identifier (required)
19
+
20
+ FLAGS
21
+ -v, --variation string Target variation (default: first variation)
22
+ -l, --label string Display label for the field (inferred from field-id if omitted)
23
+ -p, --placeholder string Placeholder text
24
+ --single string Allowed block types for single-line (comma-separated)
25
+ --multi string Allowed block types for multi-line (comma-separated)
26
+ --allow-target-blank Allow opening links in new tab
27
+ --types string Output file for generated types (default: "prismicio-types.d.ts")
28
+ -h, --help Show help for command
29
+
30
+ BLOCK TYPES
31
+ heading1, heading2, heading3, heading4, heading5, heading6,
32
+ paragraph, strong, em, preformatted, hyperlink, image, embed,
33
+ list-item, o-list-item, rtl
34
+
35
+ EXAMPLES
36
+ prismic slice add-field rich-text my_slice body
37
+ prismic slice add-field rich-text article content --multi "paragraph,heading2,heading3,strong,em,hyperlink"
38
+ prismic slice add-field rich-text hero tagline --single "heading1"
39
+ prismic slice add-field rich-text blog post --multi "paragraph,strong,em,hyperlink" --allow-target-blank
40
+ `.trim();
41
+
42
+
43
+
44
+ export async function sliceAddFieldRichText(): Promise<void> {
45
+ const {
46
+ values: {
47
+ help,
48
+ variation,
49
+ label,
50
+ placeholder,
51
+ single,
52
+ multi,
53
+ "allow-target-blank": allowTargetBlank,
54
+ types,
55
+ },
56
+ positionals: [sliceId, fieldId],
57
+ } = parseArgs({
58
+ args: process.argv.slice(5), // skip: node, script, "slice", "add-field", "rich-text"
59
+ options: {
60
+ variation: { type: "string", short: "v" },
61
+ label: { type: "string", short: "l" },
62
+ placeholder: { type: "string", short: "p" },
63
+ single: { type: "string" },
64
+ multi: { type: "string" },
65
+ "allow-target-blank": { type: "boolean" },
66
+ types: { type: "string" },
67
+ help: { type: "boolean", short: "h" },
68
+ },
69
+ allowPositionals: true,
70
+ });
71
+
72
+ if (help) {
73
+ console.info(HELP);
74
+ return;
75
+ }
76
+
77
+ if (!sliceId) {
78
+ console.error("Missing required argument: slice-id\n");
79
+ console.error("Usage: prismic slice add-field rich-text <slice-id> <field-id>");
80
+ process.exitCode = 1;
81
+ return;
82
+ }
83
+
84
+ if (!fieldId) {
85
+ console.error("Missing required argument: field-id\n");
86
+ console.error("Usage: prismic slice add-field rich-text <slice-id> <field-id>");
87
+ process.exitCode = 1;
88
+ return;
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
+
100
+ // Find the slice model
101
+ const framework = await requireFramework();
102
+ if (!framework) return;
103
+
104
+ let model: SharedSlice;
105
+ try {
106
+ model = await framework.readSlice(sliceId);
107
+ } catch {
108
+ console.error(`Slice not found: ${sliceId}\n\nCreate it first with: prismic slice create ${sliceId}`);
109
+ process.exitCode = 1;
110
+ return;
111
+ }
112
+
113
+ // Check for variations
114
+ if (model.variations.length === 0) {
115
+ console.error(`Slice "${sliceId}" has no variations.\n`);
116
+ console.error("Add a variation first before adding fields.");
117
+ process.exitCode = 1;
118
+ return;
119
+ }
120
+
121
+ // Find target variation
122
+ const targetVariation = variation
123
+ ? model.variations.find((v) => v.id === variation)
124
+ : model.variations[0];
125
+
126
+ if (!targetVariation) {
127
+ console.error(`Variation "${variation}" not found in slice "${sliceId}"\n`);
128
+ console.error(`Available variations: ${model.variations.map((v) => v.id).join(", ")}`);
129
+ process.exitCode = 1;
130
+ return;
131
+ }
132
+
133
+ // Initialize primary if it doesn't exist
134
+ if (!targetVariation.primary) {
135
+ targetVariation.primary = {};
136
+ }
137
+
138
+ // Build field definition
139
+ const fieldDefinition: RichText = {
140
+ type: "StructuredText",
141
+ config: {
142
+ label: label ?? humanReadable(fieldPath.type === "nested" ? fieldPath.nestedFieldId : fieldId),
143
+ ...(placeholder && { placeholder }),
144
+ ...(single && { single }),
145
+ ...(multi && { multi }),
146
+ ...(allowTargetBlank && { allowTargetBlank: true }),
147
+ },
148
+ };
149
+
150
+ // Add field to variation (with nested field support)
151
+ if (fieldPath.type === "nested") {
152
+ const groupResult = findGroupInVariation(targetVariation.primary, fieldPath.groupId, targetVariation.id);
153
+ if (!groupResult.ok) {
154
+ console.error(groupResult.error);
155
+ process.exitCode = 1;
156
+ return;
157
+ }
158
+ // Check if nested field already exists
159
+ if (groupResult.group.config.fields[fieldPath.nestedFieldId]) {
160
+ console.error(
161
+ `Field "${fieldPath.nestedFieldId}" already exists in group "${fieldPath.groupId}"`,
162
+ );
163
+ process.exitCode = 1;
164
+ return;
165
+ }
166
+ groupResult.group.config.fields[fieldPath.nestedFieldId] = fieldDefinition;
167
+ } else {
168
+ // Check if field already exists in any variation (at top level or in groups)
169
+ for (const v of model.variations) {
170
+ if (v.primary?.[fieldId]) {
171
+ console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
172
+ process.exitCode = 1;
173
+ return;
174
+ }
175
+ // Also check inside groups
176
+ for (const [groupFieldId, groupField] of Object.entries(v.primary ?? {})) {
177
+ if (isGroupField(groupField) && groupField.config.fields[fieldId]) {
178
+ console.error(
179
+ `Field "${fieldId}" already exists in group "${groupFieldId}" in variation "${v.id}"`,
180
+ );
181
+ process.exitCode = 1;
182
+ return;
183
+ }
184
+ }
185
+ }
186
+ targetVariation.primary[fieldId] = fieldDefinition;
187
+ }
188
+
189
+ // Write updated model
190
+ try {
191
+ await framework.updateSlice(model);
192
+ } catch (error) {
193
+ if (error instanceof Error) {
194
+ console.error(`Failed to update slice: ${error.message}`);
195
+ } else {
196
+ console.error("Failed to update slice");
197
+ }
198
+ process.exitCode = 1;
199
+ return;
200
+ }
201
+
202
+ if (fieldPath.type === "nested") {
203
+ console.info(
204
+ `Added field "${fieldPath.nestedFieldId}" (StructuredText) to group "${fieldPath.groupId}" in ${sliceId}`,
205
+ );
206
+ } else {
207
+ console.info(
208
+ `Added field "${fieldId}" (StructuredText) to "${targetVariation.id}" variation in ${sliceId}`,
209
+ );
210
+ }
211
+
212
+ try {
213
+ await buildTypes({ output: types });
214
+ console.info(`Updated types in ${types ?? "prismicio-types.d.ts"}`);
215
+ } catch (error) {
216
+ console.warn(`Could not generate types: ${error instanceof Error ? error.message : error}`);
217
+ }
218
+
219
+ console.info();
220
+ console.info("Next: Add more fields with `prismic slice add-field`");
221
+
222
+ if (framework) {
223
+ const docsPath = getDocsPath(framework.id);
224
+ const anchor = getWriteComponentsAnchor(framework.id);
225
+ console.info(
226
+ ` Run \`prismic docs fetch ${docsPath}${anchor}\` to learn how to implement the slice's component`,
227
+ );
228
+ }
229
+ }
@@ -0,0 +1,211 @@
1
+ import type { Select, SharedSlice } from "@prismicio/types-internal/lib/customtypes";
2
+
3
+ import { parseArgs } from "node:util";
4
+
5
+ import { buildTypes } from "./codegen-types";
6
+ import { findGroupInVariation, isGroupField, parseFieldPath, validateNestedFieldPath } from "./lib/field-path";
7
+ import { getDocsPath, getWriteComponentsAnchor, requireFramework } from "./framework";
8
+ import { humanReadable } from "./lib/string";
9
+
10
+ const HELP = `
11
+ Add a select (dropdown) field to an existing slice.
12
+
13
+ USAGE
14
+ prismic slice add-field select <slice-id> <field-id> [flags]
15
+
16
+ ARGUMENTS
17
+ slice-id Slice identifier (required)
18
+ field-id Field identifier (required)
19
+
20
+ FLAGS
21
+ -v, --variation string Target variation (default: first variation)
22
+ -l, --label string Display label for the field (inferred from field-id if omitted)
23
+ -p, --placeholder string Placeholder text
24
+ --option string Add an option (can be used multiple times)
25
+ --default string Default selected value
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 select my_slice layout --option "full" --option "sidebar"
31
+ prismic slice add-field select hero style --option "light" --option "dark" --default "light"
32
+ prismic slice add-field select product size --option "small" --option "medium" --option "large" --label "Size"
33
+ `.trim();
34
+
35
+
36
+
37
+ export async function sliceAddFieldSelect(): Promise<void> {
38
+ const {
39
+ values: { help, variation, label, placeholder, option, default: defaultValue, types },
40
+ positionals: [sliceId, fieldId],
41
+ } = parseArgs({
42
+ args: process.argv.slice(5), // skip: node, script, "slice", "add-field", "select"
43
+ options: {
44
+ variation: { type: "string", short: "v" },
45
+ label: { type: "string", short: "l" },
46
+ placeholder: { type: "string", short: "p" },
47
+ option: { type: "string", multiple: true },
48
+ default: { type: "string" },
49
+ types: { type: "string" },
50
+ help: { type: "boolean", short: "h" },
51
+ },
52
+ allowPositionals: true,
53
+ });
54
+
55
+ if (help) {
56
+ console.info(HELP);
57
+ return;
58
+ }
59
+
60
+ if (!sliceId) {
61
+ console.error("Missing required argument: slice-id\n");
62
+ console.error("Usage: prismic slice add-field select <slice-id> <field-id>");
63
+ process.exitCode = 1;
64
+ return;
65
+ }
66
+
67
+ if (!fieldId) {
68
+ console.error("Missing required argument: field-id\n");
69
+ console.error("Usage: prismic slice add-field select <slice-id> <field-id>");
70
+ process.exitCode = 1;
71
+ return;
72
+ }
73
+
74
+ // Parse and validate field path
75
+ const fieldPath = parseFieldPath(fieldId);
76
+ const pathValidation = validateNestedFieldPath(fieldPath);
77
+ if (!pathValidation.ok) {
78
+ console.error(pathValidation.error);
79
+ process.exitCode = 1;
80
+ return;
81
+ }
82
+
83
+ // Find the slice model
84
+ const framework = await requireFramework();
85
+ if (!framework) return;
86
+
87
+ let model: SharedSlice;
88
+ try {
89
+ model = await framework.readSlice(sliceId);
90
+ } catch {
91
+ console.error(`Slice not found: ${sliceId}\n\nCreate it first with: prismic slice create ${sliceId}`);
92
+ process.exitCode = 1;
93
+ return;
94
+ }
95
+
96
+ // Check for variations
97
+ if (model.variations.length === 0) {
98
+ console.error(`Slice "${sliceId}" has no variations.\n`);
99
+ console.error("Add a variation first before adding fields.");
100
+ process.exitCode = 1;
101
+ return;
102
+ }
103
+
104
+ // Find target variation
105
+ const targetVariation = variation
106
+ ? model.variations.find((v) => v.id === variation)
107
+ : model.variations[0];
108
+
109
+ if (!targetVariation) {
110
+ console.error(`Variation "${variation}" not found in slice "${sliceId}"\n`);
111
+ console.error(`Available variations: ${model.variations.map((v) => v.id).join(", ")}`);
112
+ process.exitCode = 1;
113
+ return;
114
+ }
115
+
116
+ // Initialize primary if it doesn't exist
117
+ if (!targetVariation.primary) {
118
+ targetVariation.primary = {};
119
+ }
120
+
121
+ // Build field definition
122
+ const fieldDefinition: Select = {
123
+ type: "Select",
124
+ config: {
125
+ label: label ?? humanReadable(fieldPath.type === "nested" ? fieldPath.nestedFieldId : fieldId),
126
+ ...(placeholder && { placeholder }),
127
+ ...(option && option.length > 0 && { options: option }),
128
+ ...(defaultValue && { default_value: defaultValue }),
129
+ },
130
+ };
131
+
132
+ // Add field to variation (with nested field support)
133
+ if (fieldPath.type === "nested") {
134
+ const groupResult = findGroupInVariation(targetVariation.primary, fieldPath.groupId, targetVariation.id);
135
+ if (!groupResult.ok) {
136
+ console.error(groupResult.error);
137
+ process.exitCode = 1;
138
+ return;
139
+ }
140
+ // Check if nested field already exists
141
+ if (groupResult.group.config.fields[fieldPath.nestedFieldId]) {
142
+ console.error(
143
+ `Field "${fieldPath.nestedFieldId}" already exists in group "${fieldPath.groupId}"`,
144
+ );
145
+ process.exitCode = 1;
146
+ return;
147
+ }
148
+ groupResult.group.config.fields[fieldPath.nestedFieldId] = fieldDefinition;
149
+ } else {
150
+ // Check if field already exists in any variation (at top level or in groups)
151
+ for (const v of model.variations) {
152
+ if (v.primary?.[fieldId]) {
153
+ console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
154
+ process.exitCode = 1;
155
+ return;
156
+ }
157
+ // Also check inside groups
158
+ for (const [groupFieldId, groupField] of Object.entries(v.primary ?? {})) {
159
+ if (isGroupField(groupField) && groupField.config.fields[fieldId]) {
160
+ console.error(
161
+ `Field "${fieldId}" already exists in group "${groupFieldId}" in variation "${v.id}"`,
162
+ );
163
+ process.exitCode = 1;
164
+ return;
165
+ }
166
+ }
167
+ }
168
+ targetVariation.primary[fieldId] = fieldDefinition;
169
+ }
170
+
171
+ // Write updated model
172
+ try {
173
+ await framework.updateSlice(model);
174
+ } catch (error) {
175
+ if (error instanceof Error) {
176
+ console.error(`Failed to update slice: ${error.message}`);
177
+ } else {
178
+ console.error("Failed to update slice");
179
+ }
180
+ process.exitCode = 1;
181
+ return;
182
+ }
183
+
184
+ if (fieldPath.type === "nested") {
185
+ console.info(
186
+ `Added field "${fieldPath.nestedFieldId}" (Select) to group "${fieldPath.groupId}" in ${sliceId}`,
187
+ );
188
+ } else {
189
+ console.info(
190
+ `Added field "${fieldId}" (Select) to "${targetVariation.id}" variation in ${sliceId}`,
191
+ );
192
+ }
193
+
194
+ try {
195
+ await buildTypes({ output: types });
196
+ console.info(`Updated types in ${types ?? "prismicio-types.d.ts"}`);
197
+ } catch (error) {
198
+ console.warn(`Could not generate types: ${error instanceof Error ? error.message : error}`);
199
+ }
200
+
201
+ console.info();
202
+ console.info("Next: Add more fields with `prismic slice add-field`");
203
+
204
+ if (framework) {
205
+ const docsPath = getDocsPath(framework.id);
206
+ const anchor = getWriteComponentsAnchor(framework.id);
207
+ console.info(
208
+ ` Run \`prismic docs fetch ${docsPath}${anchor}\` to learn how to implement the slice's component`,
209
+ );
210
+ }
211
+ }