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,202 @@
1
+ import type { Image, 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 an image field to an existing slice.
12
+
13
+ USAGE
14
+ prismic slice add-field image <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
+ --types string Output file for generated types (default: "prismicio-types.d.ts")
24
+ -h, --help Show help for command
25
+
26
+ EXAMPLES
27
+ prismic slice add-field image my_slice background
28
+ prismic slice add-field image hero banner --label "Hero Banner"
29
+ prismic slice add-field image gallery thumbnail --variation "grid"
30
+ `.trim();
31
+
32
+
33
+
34
+ export async function sliceAddFieldImage(): Promise<void> {
35
+ const {
36
+ values: { help, variation, label, types },
37
+ positionals: [sliceId, fieldId],
38
+ } = parseArgs({
39
+ args: process.argv.slice(5), // skip: node, script, "slice", "add-field", "image"
40
+ options: {
41
+ variation: { type: "string", short: "v" },
42
+ label: { type: "string", short: "l" },
43
+ types: { type: "string" },
44
+ help: { type: "boolean", short: "h" },
45
+ },
46
+ allowPositionals: true,
47
+ });
48
+
49
+ if (help) {
50
+ console.info(HELP);
51
+ return;
52
+ }
53
+
54
+ if (!sliceId) {
55
+ console.error("Missing required argument: slice-id\n");
56
+ console.error("Usage: prismic slice add-field image <slice-id> <field-id>");
57
+ process.exitCode = 1;
58
+ return;
59
+ }
60
+
61
+ if (!fieldId) {
62
+ console.error("Missing required argument: field-id\n");
63
+ console.error("Usage: prismic slice add-field image <slice-id> <field-id>");
64
+ process.exitCode = 1;
65
+ return;
66
+ }
67
+
68
+ // Parse and validate field path
69
+ const fieldPath = parseFieldPath(fieldId);
70
+ const pathValidation = validateNestedFieldPath(fieldPath);
71
+ if (!pathValidation.ok) {
72
+ console.error(pathValidation.error);
73
+ process.exitCode = 1;
74
+ return;
75
+ }
76
+
77
+ // Find the slice model
78
+ const framework = await requireFramework();
79
+ if (!framework) return;
80
+
81
+ let model: SharedSlice;
82
+ try {
83
+ model = await framework.readSlice(sliceId);
84
+ } catch {
85
+ console.error(`Slice not found: ${sliceId}\n\nCreate it first with: prismic slice create ${sliceId}`);
86
+ process.exitCode = 1;
87
+ return;
88
+ }
89
+
90
+ // Check for variations
91
+ if (model.variations.length === 0) {
92
+ console.error(`Slice "${sliceId}" has no variations.\n`);
93
+ console.error("Add a variation first before adding fields.");
94
+ process.exitCode = 1;
95
+ return;
96
+ }
97
+
98
+ // Find target variation
99
+ const targetVariation = variation
100
+ ? model.variations.find((v) => v.id === variation)
101
+ : model.variations[0];
102
+
103
+ if (!targetVariation) {
104
+ console.error(`Variation "${variation}" not found in slice "${sliceId}"\n`);
105
+ console.error(`Available variations: ${model.variations.map((v) => v.id).join(", ")}`);
106
+ process.exitCode = 1;
107
+ return;
108
+ }
109
+
110
+ // Initialize primary if it doesn't exist
111
+ if (!targetVariation.primary) {
112
+ targetVariation.primary = {};
113
+ }
114
+
115
+ // Build field definition
116
+ const fieldDefinition: Image = {
117
+ type: "Image",
118
+ config: {
119
+ label: label ?? humanReadable(fieldPath.type === "nested" ? fieldPath.nestedFieldId : fieldId),
120
+ },
121
+ };
122
+
123
+ // Add field to variation (with nested field support)
124
+ if (fieldPath.type === "nested") {
125
+ const groupResult = findGroupInVariation(targetVariation.primary, fieldPath.groupId, targetVariation.id);
126
+ if (!groupResult.ok) {
127
+ console.error(groupResult.error);
128
+ process.exitCode = 1;
129
+ return;
130
+ }
131
+ // Check if nested field already exists
132
+ if (groupResult.group.config.fields[fieldPath.nestedFieldId]) {
133
+ console.error(
134
+ `Field "${fieldPath.nestedFieldId}" already exists in group "${fieldPath.groupId}"`,
135
+ );
136
+ process.exitCode = 1;
137
+ return;
138
+ }
139
+ groupResult.group.config.fields[fieldPath.nestedFieldId] = fieldDefinition;
140
+ } else {
141
+ // Check if field already exists in any variation (at top level or in groups)
142
+ for (const v of model.variations) {
143
+ if (v.primary?.[fieldId]) {
144
+ console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
145
+ process.exitCode = 1;
146
+ return;
147
+ }
148
+ // Also check inside groups
149
+ for (const [groupFieldId, groupField] of Object.entries(v.primary ?? {})) {
150
+ if (isGroupField(groupField) && groupField.config.fields[fieldId]) {
151
+ console.error(
152
+ `Field "${fieldId}" already exists in group "${groupFieldId}" in variation "${v.id}"`,
153
+ );
154
+ process.exitCode = 1;
155
+ return;
156
+ }
157
+ }
158
+ }
159
+ targetVariation.primary[fieldId] = fieldDefinition;
160
+ }
161
+
162
+ // Write updated model
163
+ try {
164
+ await framework.updateSlice(model);
165
+ } catch (error) {
166
+ if (error instanceof Error) {
167
+ console.error(`Failed to update slice: ${error.message}`);
168
+ } else {
169
+ console.error("Failed to update slice");
170
+ }
171
+ process.exitCode = 1;
172
+ return;
173
+ }
174
+
175
+ if (fieldPath.type === "nested") {
176
+ console.info(
177
+ `Added field "${fieldPath.nestedFieldId}" (Image) to group "${fieldPath.groupId}" in ${sliceId}`,
178
+ );
179
+ } else {
180
+ console.info(
181
+ `Added field "${fieldId}" (Image) to "${targetVariation.id}" variation in ${sliceId}`,
182
+ );
183
+ }
184
+
185
+ try {
186
+ await buildTypes({ output: types });
187
+ console.info(`Updated types in ${types ?? "prismicio-types.d.ts"}`);
188
+ } catch (error) {
189
+ console.warn(`Could not generate types: ${error instanceof Error ? error.message : error}`);
190
+ }
191
+
192
+ console.info();
193
+ console.info("Next: Add more fields with `prismic slice add-field`");
194
+
195
+ if (framework) {
196
+ const docsPath = getDocsPath(framework.id);
197
+ const anchor = getWriteComponentsAnchor(framework.id);
198
+ console.info(
199
+ ` Run \`prismic docs fetch ${docsPath}${anchor}\` to learn how to implement the slice's component`,
200
+ );
201
+ }
202
+ }
@@ -0,0 +1,205 @@
1
+ import type { SharedSlice, Text } 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 key-text (single-line text) field to an existing slice.
12
+
13
+ USAGE
14
+ prismic slice add-field key-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
+ --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 key-text my_slice title
29
+ prismic slice add-field key-text hero heading --label "Heading"
30
+ prismic slice add-field key-text cta button_text --placeholder "Enter button text"
31
+ `.trim();
32
+
33
+
34
+
35
+ export async function sliceAddFieldKeyText(): 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", "key-text"
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 key-text <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 key-text <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: Text = {
119
+ type: "Text",
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}" (Text) to group "${fieldPath.groupId}" in ${sliceId}`,
181
+ );
182
+ } else {
183
+ console.info(
184
+ `Added field "${fieldId}" (Text) 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,224 @@
1
+ import type { Link, 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 link field to an existing slice.
12
+
13
+ USAGE
14
+ prismic slice add-field link <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
+ --allow-text Allow text with link
25
+ --allow-target-blank Allow opening link in new tab
26
+ --repeatable Allow multiple links
27
+ --types string Output file for generated types (default: "prismicio-types.d.ts")
28
+ -h, --help Show help for command
29
+
30
+ EXAMPLES
31
+ prismic slice add-field link my_slice button
32
+ prismic slice add-field link cta primary_link --allow-text
33
+ prismic slice add-field link navigation links --repeatable
34
+ prismic slice add-field link hero cta --allow-text --allow-target-blank
35
+ `.trim();
36
+
37
+
38
+
39
+ export async function sliceAddFieldLink(): Promise<void> {
40
+ const {
41
+ values: {
42
+ help,
43
+ variation,
44
+ label,
45
+ placeholder,
46
+ "allow-text": allowText,
47
+ "allow-target-blank": allowTargetBlank,
48
+ repeatable,
49
+ types,
50
+ },
51
+ positionals: [sliceId, fieldId],
52
+ } = parseArgs({
53
+ args: process.argv.slice(5), // skip: node, script, "slice", "add-field", "link"
54
+ options: {
55
+ variation: { type: "string", short: "v" },
56
+ label: { type: "string", short: "l" },
57
+ placeholder: { type: "string", short: "p" },
58
+ "allow-text": { type: "boolean" },
59
+ "allow-target-blank": { type: "boolean" },
60
+ repeatable: { type: "boolean" },
61
+ types: { type: "string" },
62
+ help: { type: "boolean", short: "h" },
63
+ },
64
+ allowPositionals: true,
65
+ });
66
+
67
+ if (help) {
68
+ console.info(HELP);
69
+ return;
70
+ }
71
+
72
+ if (!sliceId) {
73
+ console.error("Missing required argument: slice-id\n");
74
+ console.error("Usage: prismic slice add-field link <slice-id> <field-id>");
75
+ process.exitCode = 1;
76
+ return;
77
+ }
78
+
79
+ if (!fieldId) {
80
+ console.error("Missing required argument: field-id\n");
81
+ console.error("Usage: prismic slice add-field link <slice-id> <field-id>");
82
+ process.exitCode = 1;
83
+ return;
84
+ }
85
+
86
+ // Parse and validate field path
87
+ const fieldPath = parseFieldPath(fieldId);
88
+ const pathValidation = validateNestedFieldPath(fieldPath);
89
+ if (!pathValidation.ok) {
90
+ console.error(pathValidation.error);
91
+ process.exitCode = 1;
92
+ return;
93
+ }
94
+
95
+ // Find the slice model
96
+ const framework = await requireFramework();
97
+ if (!framework) return;
98
+
99
+ let model: SharedSlice;
100
+ try {
101
+ model = await framework.readSlice(sliceId);
102
+ } catch {
103
+ console.error(`Slice not found: ${sliceId}\n\nCreate it first with: prismic slice create ${sliceId}`);
104
+ process.exitCode = 1;
105
+ return;
106
+ }
107
+
108
+ // Check for variations
109
+ if (model.variations.length === 0) {
110
+ console.error(`Slice "${sliceId}" has no variations.\n`);
111
+ console.error("Add a variation first before adding fields.");
112
+ process.exitCode = 1;
113
+ return;
114
+ }
115
+
116
+ // Find target variation
117
+ const targetVariation = variation
118
+ ? model.variations.find((v) => v.id === variation)
119
+ : model.variations[0];
120
+
121
+ if (!targetVariation) {
122
+ console.error(`Variation "${variation}" not found in slice "${sliceId}"\n`);
123
+ console.error(`Available variations: ${model.variations.map((v) => v.id).join(", ")}`);
124
+ process.exitCode = 1;
125
+ return;
126
+ }
127
+
128
+ // Initialize primary if it doesn't exist
129
+ if (!targetVariation.primary) {
130
+ targetVariation.primary = {};
131
+ }
132
+
133
+ // Build field definition
134
+ const fieldDefinition: Link = {
135
+ type: "Link",
136
+ config: {
137
+ label: label ?? humanReadable(fieldPath.type === "nested" ? fieldPath.nestedFieldId : fieldId),
138
+ ...(placeholder && { placeholder }),
139
+ ...(allowText && { allowText: true }),
140
+ ...(allowTargetBlank && { allowTargetBlank: true }),
141
+ ...(repeatable && { repeat: true }),
142
+ },
143
+ };
144
+
145
+ // Add field to variation (with nested field support)
146
+ if (fieldPath.type === "nested") {
147
+ const groupResult = findGroupInVariation(targetVariation.primary, fieldPath.groupId, targetVariation.id);
148
+ if (!groupResult.ok) {
149
+ console.error(groupResult.error);
150
+ process.exitCode = 1;
151
+ return;
152
+ }
153
+ // Check if nested field already exists
154
+ if (groupResult.group.config.fields[fieldPath.nestedFieldId]) {
155
+ console.error(
156
+ `Field "${fieldPath.nestedFieldId}" already exists in group "${fieldPath.groupId}"`,
157
+ );
158
+ process.exitCode = 1;
159
+ return;
160
+ }
161
+ groupResult.group.config.fields[fieldPath.nestedFieldId] = fieldDefinition;
162
+ } else {
163
+ // Check if field already exists in any variation (at top level or in groups)
164
+ for (const v of model.variations) {
165
+ if (v.primary?.[fieldId]) {
166
+ console.error(`Field "${fieldId}" already exists in variation "${v.id}"`);
167
+ process.exitCode = 1;
168
+ return;
169
+ }
170
+ // Also check inside groups
171
+ for (const [groupFieldId, groupField] of Object.entries(v.primary ?? {})) {
172
+ if (isGroupField(groupField) && groupField.config.fields[fieldId]) {
173
+ console.error(
174
+ `Field "${fieldId}" already exists in group "${groupFieldId}" in variation "${v.id}"`,
175
+ );
176
+ process.exitCode = 1;
177
+ return;
178
+ }
179
+ }
180
+ }
181
+ targetVariation.primary[fieldId] = fieldDefinition;
182
+ }
183
+
184
+ // Write updated model
185
+ try {
186
+ await framework.updateSlice(model);
187
+ } catch (error) {
188
+ if (error instanceof Error) {
189
+ console.error(`Failed to update slice: ${error.message}`);
190
+ } else {
191
+ console.error("Failed to update slice");
192
+ }
193
+ process.exitCode = 1;
194
+ return;
195
+ }
196
+
197
+ if (fieldPath.type === "nested") {
198
+ console.info(
199
+ `Added field "${fieldPath.nestedFieldId}" (Link) to group "${fieldPath.groupId}" in ${sliceId}`,
200
+ );
201
+ } else {
202
+ console.info(
203
+ `Added field "${fieldId}" (Link) to "${targetVariation.id}" variation in ${sliceId}`,
204
+ );
205
+ }
206
+
207
+ try {
208
+ await buildTypes({ output: types });
209
+ console.info(`Updated types in ${types ?? "prismicio-types.d.ts"}`);
210
+ } catch (error) {
211
+ console.warn(`Could not generate types: ${error instanceof Error ? error.message : error}`);
212
+ }
213
+
214
+ console.info();
215
+ console.info("Next: Add more fields with `prismic slice add-field`");
216
+
217
+ if (framework) {
218
+ const docsPath = getDocsPath(framework.id);
219
+ const anchor = getWriteComponentsAnchor(framework.id);
220
+ console.info(
221
+ ` Run \`prismic docs fetch ${docsPath}${anchor}\` to learn how to implement the slice's component`,
222
+ );
223
+ }
224
+ }