@angeloashmore/prismic-cli-poc 0.0.0-canary.1d36cd8

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 (131) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +98 -0
  3. package/dist/index.mjs +2548 -0
  4. package/package.json +53 -0
  5. package/src/codegen-types.ts +82 -0
  6. package/src/codegen.ts +45 -0
  7. package/src/custom-type-add-field-boolean.ts +192 -0
  8. package/src/custom-type-add-field-color.ts +177 -0
  9. package/src/custom-type-add-field-date.ts +180 -0
  10. package/src/custom-type-add-field-embed.ts +177 -0
  11. package/src/custom-type-add-field-geo-point.ts +174 -0
  12. package/src/custom-type-add-field-image.ts +177 -0
  13. package/src/custom-type-add-field-key-text.ts +177 -0
  14. package/src/custom-type-add-field-link.ts +201 -0
  15. package/src/custom-type-add-field-number.ts +209 -0
  16. package/src/custom-type-add-field-rich-text.ts +202 -0
  17. package/src/custom-type-add-field-select.ts +192 -0
  18. package/src/custom-type-add-field-timestamp.ts +180 -0
  19. package/src/custom-type-add-field-uid.ts +177 -0
  20. package/src/custom-type-add-field.ts +111 -0
  21. package/src/custom-type-connect-slice.ts +220 -0
  22. package/src/custom-type-create.ts +118 -0
  23. package/src/custom-type-disconnect-slice.ts +177 -0
  24. package/src/custom-type-list.ts +110 -0
  25. package/src/custom-type-remove-field.ts +177 -0
  26. package/src/custom-type-remove.ts +144 -0
  27. package/src/custom-type-set-name.ts +144 -0
  28. package/src/custom-type-view.ts +118 -0
  29. package/src/custom-type.ts +85 -0
  30. package/src/index.ts +127 -0
  31. package/src/init.ts +64 -0
  32. package/src/lib/auth.ts +83 -0
  33. package/src/lib/config.ts +111 -0
  34. package/src/lib/custom-types-api.ts +438 -0
  35. package/src/lib/file.ts +49 -0
  36. package/src/lib/framework.ts +143 -0
  37. package/src/lib/json.ts +3 -0
  38. package/src/lib/request.ts +116 -0
  39. package/src/lib/slice.ts +115 -0
  40. package/src/lib/string.ts +6 -0
  41. package/src/lib/url.ts +25 -0
  42. package/src/locale-add.ts +116 -0
  43. package/src/locale-list.ts +107 -0
  44. package/src/locale-remove.ts +88 -0
  45. package/src/locale-set-default.ts +131 -0
  46. package/src/locale.ts +60 -0
  47. package/src/login.ts +152 -0
  48. package/src/logout.ts +36 -0
  49. package/src/page-type-add-field-boolean.ts +192 -0
  50. package/src/page-type-add-field-color.ts +177 -0
  51. package/src/page-type-add-field-date.ts +180 -0
  52. package/src/page-type-add-field-embed.ts +177 -0
  53. package/src/page-type-add-field-geo-point.ts +174 -0
  54. package/src/page-type-add-field-image.ts +177 -0
  55. package/src/page-type-add-field-key-text.ts +177 -0
  56. package/src/page-type-add-field-link.ts +201 -0
  57. package/src/page-type-add-field-number.ts +209 -0
  58. package/src/page-type-add-field-rich-text.ts +202 -0
  59. package/src/page-type-add-field-select.ts +192 -0
  60. package/src/page-type-add-field-timestamp.ts +180 -0
  61. package/src/page-type-add-field-uid.ts +177 -0
  62. package/src/page-type-add-field.ts +111 -0
  63. package/src/page-type-connect-slice.ts +220 -0
  64. package/src/page-type-create.ts +142 -0
  65. package/src/page-type-disconnect-slice.ts +177 -0
  66. package/src/page-type-list.ts +109 -0
  67. package/src/page-type-remove-field.ts +177 -0
  68. package/src/page-type-remove.ts +144 -0
  69. package/src/page-type-set-name.ts +144 -0
  70. package/src/page-type-set-repeatable.ts +153 -0
  71. package/src/page-type-view.ts +118 -0
  72. package/src/page-type.ts +90 -0
  73. package/src/preview-add.ts +126 -0
  74. package/src/preview-get-simulator.ts +104 -0
  75. package/src/preview-list.ts +106 -0
  76. package/src/preview-remove-simulator.ts +80 -0
  77. package/src/preview-remove.ts +109 -0
  78. package/src/preview-set-name.ts +137 -0
  79. package/src/preview-set-simulator.ts +116 -0
  80. package/src/preview.ts +75 -0
  81. package/src/pull.ts +247 -0
  82. package/src/push.ts +405 -0
  83. package/src/repo-create.ts +136 -0
  84. package/src/repo-get-access.ts +86 -0
  85. package/src/repo-list.ts +100 -0
  86. package/src/repo-set-access.ts +100 -0
  87. package/src/repo-set-name.ts +102 -0
  88. package/src/repo-view.ts +113 -0
  89. package/src/repo.ts +70 -0
  90. package/src/slice-add-field-boolean.ts +173 -0
  91. package/src/slice-add-field-color.ts +158 -0
  92. package/src/slice-add-field-date.ts +158 -0
  93. package/src/slice-add-field-embed.ts +158 -0
  94. package/src/slice-add-field-geo-point.ts +155 -0
  95. package/src/slice-add-field-image.ts +155 -0
  96. package/src/slice-add-field-key-text.ts +158 -0
  97. package/src/slice-add-field-link.ts +178 -0
  98. package/src/slice-add-field-number.ts +158 -0
  99. package/src/slice-add-field-rich-text.ts +183 -0
  100. package/src/slice-add-field-select.ts +173 -0
  101. package/src/slice-add-field-timestamp.ts +158 -0
  102. package/src/slice-add-field.ts +106 -0
  103. package/src/slice-add-variation.ts +145 -0
  104. package/src/slice-create.ts +148 -0
  105. package/src/slice-list-variations.ts +67 -0
  106. package/src/slice-list.ts +88 -0
  107. package/src/slice-remove-field.ts +128 -0
  108. package/src/slice-remove-variation.ts +118 -0
  109. package/src/slice-remove.ts +97 -0
  110. package/src/slice-rename.ts +128 -0
  111. package/src/slice-view.ts +77 -0
  112. package/src/slice.ts +90 -0
  113. package/src/status.ts +733 -0
  114. package/src/token-create.ts +203 -0
  115. package/src/token-delete.ts +182 -0
  116. package/src/token-list.ts +223 -0
  117. package/src/token-set-name.ts +193 -0
  118. package/src/token.ts +60 -0
  119. package/src/webhook-add-header.ts +118 -0
  120. package/src/webhook-create.ts +152 -0
  121. package/src/webhook-disable.ts +109 -0
  122. package/src/webhook-enable.ts +132 -0
  123. package/src/webhook-list.ts +93 -0
  124. package/src/webhook-remove-header.ts +117 -0
  125. package/src/webhook-remove.ts +106 -0
  126. package/src/webhook-set-triggers.ts +148 -0
  127. package/src/webhook-status.ts +90 -0
  128. package/src/webhook-test.ts +106 -0
  129. package/src/webhook-view.ts +147 -0
  130. package/src/webhook.ts +95 -0
  131. package/src/whoami.ts +62 -0
@@ -0,0 +1,177 @@
1
+ import type { Color, CustomType } from "@prismicio/types-internal/lib/customtypes";
2
+
3
+ import { readFile, writeFile } from "node:fs/promises";
4
+ import { parseArgs } from "node:util";
5
+ import * as v from "valibot";
6
+
7
+ import { buildTypes } from "./codegen-types";
8
+ import { findUpward } from "./lib/file";
9
+ import { stringify } from "./lib/json";
10
+ import { humanReadable } from "./lib/string";
11
+
12
+ const HELP = `
13
+ Add a color picker field to an existing page type.
14
+
15
+ USAGE
16
+ prismic page-type add-field color <type-id> <field-id> [flags]
17
+
18
+ ARGUMENTS
19
+ type-id Page type identifier (required)
20
+ field-id Field identifier (required)
21
+
22
+ Types are generated by default after changes. Use --no-types to skip.
23
+
24
+ FLAGS
25
+ -t, --tab string Target tab (default: first existing tab, or "Main")
26
+ -l, --label string Display label for the field (inferred from field-id if omitted)
27
+ -p, --placeholder string Placeholder text
28
+ --types string Output file for generated types (default: "prismicio-types.d.ts")
29
+ --no-types Skip type generation
30
+ -h, --help Show help for command
31
+
32
+ EXAMPLES
33
+ prismic page-type add-field color homepage bg_color
34
+ prismic page-type add-field color homepage accent --tab "Design"
35
+ prismic page-type add-field color homepage text_color --label "Text Color"
36
+ `.trim();
37
+
38
+ const CustomTypeSchema = v.object({
39
+ id: v.string(),
40
+ label: v.string(),
41
+ repeatable: v.boolean(),
42
+ status: v.boolean(),
43
+ format: v.string(),
44
+ json: v.record(v.string(), v.record(v.string(), v.unknown())),
45
+ });
46
+
47
+ export async function pageTypeAddFieldColor(): Promise<void> {
48
+ const {
49
+ values: { help, tab, label, placeholder, types, "no-types": noTypes },
50
+ positionals: [typeId, fieldId],
51
+ } = parseArgs({
52
+ args: process.argv.slice(5), // skip: node, script, "page-type", "add-field", "color"
53
+ options: {
54
+ tab: { type: "string", short: "t" },
55
+ label: { type: "string", short: "l" },
56
+ placeholder: { type: "string", short: "p" },
57
+ types: { type: "string" },
58
+ "no-types": { type: "boolean" },
59
+ help: { type: "boolean", short: "h" },
60
+ },
61
+ allowPositionals: true,
62
+ });
63
+
64
+ if (help) {
65
+ console.info(HELP);
66
+ return;
67
+ }
68
+
69
+ if (!typeId) {
70
+ console.error("Missing required argument: type-id\n");
71
+ console.error("Usage: prismic page-type add-field color <type-id> <field-id>");
72
+ process.exitCode = 1;
73
+ return;
74
+ }
75
+
76
+ if (!fieldId) {
77
+ console.error("Missing required argument: field-id\n");
78
+ console.error("Usage: prismic page-type add-field color <type-id> <field-id>");
79
+ process.exitCode = 1;
80
+ return;
81
+ }
82
+
83
+ // Find the page type file
84
+ const projectRoot = await findUpward("package.json");
85
+ if (!projectRoot) {
86
+ console.error("Could not find project root (no package.json found)");
87
+ process.exitCode = 1;
88
+ return;
89
+ }
90
+
91
+ const modelPath = new URL(`customtypes/${typeId}/index.json`, projectRoot);
92
+
93
+ // Read and parse the model
94
+ let model: CustomType;
95
+ try {
96
+ const contents = await readFile(modelPath, "utf8");
97
+ const result = v.safeParse(CustomTypeSchema, JSON.parse(contents));
98
+ if (!result.success) {
99
+ console.error(`Invalid page type model: ${modelPath.href}`);
100
+ process.exitCode = 1;
101
+ return;
102
+ }
103
+ model = result.output as CustomType;
104
+ } catch (error) {
105
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
106
+ console.error(`Page type not found: ${typeId}\n`);
107
+ console.error(`Create it first with: prismic page-type create ${typeId}`);
108
+ process.exitCode = 1;
109
+ return;
110
+ }
111
+ if (error instanceof Error) {
112
+ console.error(`Failed to read page type: ${error.message}`);
113
+ } else {
114
+ console.error("Failed to read page type");
115
+ }
116
+ process.exitCode = 1;
117
+ return;
118
+ }
119
+
120
+ // Determine target tab
121
+ const existingTabs = Object.keys(model.json);
122
+ const targetTab = tab ?? existingTabs[0] ?? "Main";
123
+
124
+ // Initialize tab if it doesn't exist
125
+ if (!model.json[targetTab]) {
126
+ model.json[targetTab] = {};
127
+ }
128
+
129
+ // Check if field already exists in any tab
130
+ for (const [tabName, tabFields] of Object.entries(model.json)) {
131
+ if (tabFields[fieldId]) {
132
+ console.error(`Field "${fieldId}" already exists in tab "${tabName}"`);
133
+ process.exitCode = 1;
134
+ return;
135
+ }
136
+ }
137
+
138
+ // Build field definition
139
+ const fieldDefinition: Color = {
140
+ type: "Color",
141
+ config: {
142
+ label: label ?? humanReadable(fieldId),
143
+ ...(placeholder && { placeholder }),
144
+ },
145
+ };
146
+
147
+ // Add field to model
148
+ model.json[targetTab][fieldId] = fieldDefinition;
149
+
150
+ // Write updated model
151
+ try {
152
+ await writeFile(modelPath, stringify(model));
153
+ } catch (error) {
154
+ if (error instanceof Error) {
155
+ console.error(`Failed to update page type: ${error.message}`);
156
+ } else {
157
+ console.error("Failed to update page type");
158
+ }
159
+ process.exitCode = 1;
160
+ return;
161
+ }
162
+
163
+ console.info(`Added field "${fieldId}" (Color) to "${targetTab}" tab in ${typeId}`);
164
+
165
+ if (!noTypes) {
166
+ try {
167
+ await buildTypes({ output: types });
168
+ console.info(`Updated types in ${types ?? "prismicio-types.d.ts"}`);
169
+ } catch (error) {
170
+ console.warn(`Could not generate types: ${error instanceof Error ? error.message : error}`);
171
+ }
172
+ }
173
+
174
+ console.info();
175
+ console.info("Next: Add more fields with `prismic page-type add-field`");
176
+ console.info(" Run `prismic status` when done to find next steps");
177
+ }
@@ -0,0 +1,180 @@
1
+ import type { CustomType, Date as DateField } from "@prismicio/types-internal/lib/customtypes";
2
+
3
+ import { readFile, writeFile } from "node:fs/promises";
4
+ import { parseArgs } from "node:util";
5
+ import * as v from "valibot";
6
+
7
+ import { buildTypes } from "./codegen-types";
8
+ import { findUpward } from "./lib/file";
9
+ import { stringify } from "./lib/json";
10
+ import { humanReadable } from "./lib/string";
11
+
12
+ const HELP = `
13
+ Add a date field to an existing page type.
14
+
15
+ USAGE
16
+ prismic page-type add-field date <type-id> <field-id> [flags]
17
+
18
+ ARGUMENTS
19
+ type-id Page type identifier (required)
20
+ field-id Field identifier (required)
21
+
22
+ Types are generated by default after changes. Use --no-types to skip.
23
+
24
+ FLAGS
25
+ -t, --tab string Target tab (default: first existing tab, or "Main")
26
+ -l, --label string Display label for the field (inferred from field-id if omitted)
27
+ -p, --placeholder string Placeholder text
28
+ --default string Default date value (YYYY-MM-DD format)
29
+ --types string Output file for generated types (default: "prismicio-types.d.ts")
30
+ --no-types Skip type generation
31
+ -h, --help Show help for command
32
+
33
+ EXAMPLES
34
+ prismic page-type add-field date homepage publish_date
35
+ prismic page-type add-field date event start_date --tab "Schedule"
36
+ prismic page-type add-field date article date --label "Publication Date" --default "2024-01-01"
37
+ `.trim();
38
+
39
+ const CustomTypeSchema = v.object({
40
+ id: v.string(),
41
+ label: v.string(),
42
+ repeatable: v.boolean(),
43
+ status: v.boolean(),
44
+ format: v.string(),
45
+ json: v.record(v.string(), v.record(v.string(), v.unknown())),
46
+ });
47
+
48
+ export async function pageTypeAddFieldDate(): Promise<void> {
49
+ const {
50
+ values: { help, tab, label, placeholder, default: defaultValue, types, "no-types": noTypes },
51
+ positionals: [typeId, fieldId],
52
+ } = parseArgs({
53
+ args: process.argv.slice(5), // skip: node, script, "page-type", "add-field", "date"
54
+ options: {
55
+ tab: { type: "string", short: "t" },
56
+ label: { type: "string", short: "l" },
57
+ placeholder: { type: "string", short: "p" },
58
+ default: { type: "string" },
59
+ types: { type: "string" },
60
+ "no-types": { type: "boolean" },
61
+ help: { type: "boolean", short: "h" },
62
+ },
63
+ allowPositionals: true,
64
+ });
65
+
66
+ if (help) {
67
+ console.info(HELP);
68
+ return;
69
+ }
70
+
71
+ if (!typeId) {
72
+ console.error("Missing required argument: type-id\n");
73
+ console.error("Usage: prismic page-type add-field date <type-id> <field-id>");
74
+ process.exitCode = 1;
75
+ return;
76
+ }
77
+
78
+ if (!fieldId) {
79
+ console.error("Missing required argument: field-id\n");
80
+ console.error("Usage: prismic page-type add-field date <type-id> <field-id>");
81
+ process.exitCode = 1;
82
+ return;
83
+ }
84
+
85
+ // Find the page type file
86
+ const projectRoot = await findUpward("package.json");
87
+ if (!projectRoot) {
88
+ console.error("Could not find project root (no package.json found)");
89
+ process.exitCode = 1;
90
+ return;
91
+ }
92
+
93
+ const modelPath = new URL(`customtypes/${typeId}/index.json`, projectRoot);
94
+
95
+ // Read and parse the model
96
+ let model: CustomType;
97
+ try {
98
+ const contents = await readFile(modelPath, "utf8");
99
+ const result = v.safeParse(CustomTypeSchema, JSON.parse(contents));
100
+ if (!result.success) {
101
+ console.error(`Invalid page type model: ${modelPath.href}`);
102
+ process.exitCode = 1;
103
+ return;
104
+ }
105
+ model = result.output as CustomType;
106
+ } catch (error) {
107
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
108
+ console.error(`Page type not found: ${typeId}\n`);
109
+ console.error(`Create it first with: prismic page-type create ${typeId}`);
110
+ process.exitCode = 1;
111
+ return;
112
+ }
113
+ if (error instanceof Error) {
114
+ console.error(`Failed to read page type: ${error.message}`);
115
+ } else {
116
+ console.error("Failed to read page type");
117
+ }
118
+ process.exitCode = 1;
119
+ return;
120
+ }
121
+
122
+ // Determine target tab
123
+ const existingTabs = Object.keys(model.json);
124
+ const targetTab = tab ?? existingTabs[0] ?? "Main";
125
+
126
+ // Initialize tab if it doesn't exist
127
+ if (!model.json[targetTab]) {
128
+ model.json[targetTab] = {};
129
+ }
130
+
131
+ // Check if field already exists in any tab
132
+ for (const [tabName, tabFields] of Object.entries(model.json)) {
133
+ if (tabFields[fieldId]) {
134
+ console.error(`Field "${fieldId}" already exists in tab "${tabName}"`);
135
+ process.exitCode = 1;
136
+ return;
137
+ }
138
+ }
139
+
140
+ // Build field definition
141
+ const fieldDefinition: DateField = {
142
+ type: "Date",
143
+ config: {
144
+ label: label ?? humanReadable(fieldId),
145
+ ...(placeholder && { placeholder }),
146
+ ...(defaultValue && { default: defaultValue }),
147
+ },
148
+ };
149
+
150
+ // Add field to model
151
+ model.json[targetTab][fieldId] = fieldDefinition;
152
+
153
+ // Write updated model
154
+ try {
155
+ await writeFile(modelPath, stringify(model));
156
+ } catch (error) {
157
+ if (error instanceof Error) {
158
+ console.error(`Failed to update page type: ${error.message}`);
159
+ } else {
160
+ console.error("Failed to update page type");
161
+ }
162
+ process.exitCode = 1;
163
+ return;
164
+ }
165
+
166
+ console.info(`Added field "${fieldId}" (Date) to "${targetTab}" tab in ${typeId}`);
167
+
168
+ if (!noTypes) {
169
+ try {
170
+ await buildTypes({ output: types });
171
+ console.info(`Updated types in ${types ?? "prismicio-types.d.ts"}`);
172
+ } catch (error) {
173
+ console.warn(`Could not generate types: ${error instanceof Error ? error.message : error}`);
174
+ }
175
+ }
176
+
177
+ console.info();
178
+ console.info("Next: Add more fields with `prismic page-type add-field`");
179
+ console.info(" Run `prismic status` when done to find next steps");
180
+ }
@@ -0,0 +1,177 @@
1
+ import type { CustomType, Embed } from "@prismicio/types-internal/lib/customtypes";
2
+
3
+ import { readFile, writeFile } from "node:fs/promises";
4
+ import { parseArgs } from "node:util";
5
+ import * as v from "valibot";
6
+
7
+ import { buildTypes } from "./codegen-types";
8
+ import { findUpward } from "./lib/file";
9
+ import { stringify } from "./lib/json";
10
+ import { humanReadable } from "./lib/string";
11
+
12
+ const HELP = `
13
+ Add an embed field to an existing page type.
14
+
15
+ USAGE
16
+ prismic page-type add-field embed <type-id> <field-id> [flags]
17
+
18
+ ARGUMENTS
19
+ type-id Page type identifier (required)
20
+ field-id Field identifier (required)
21
+
22
+ Types are generated by default after changes. Use --no-types to skip.
23
+
24
+ FLAGS
25
+ -t, --tab string Target tab (default: first existing tab, or "Main")
26
+ -l, --label string Display label for the field (inferred from field-id if omitted)
27
+ -p, --placeholder string Placeholder text
28
+ --types string Output file for generated types (default: "prismicio-types.d.ts")
29
+ --no-types Skip type generation
30
+ -h, --help Show help for command
31
+
32
+ EXAMPLES
33
+ prismic page-type add-field embed homepage video
34
+ prismic page-type add-field embed homepage youtube --tab "Media"
35
+ prismic page-type add-field embed homepage media --label "Media Embed"
36
+ `.trim();
37
+
38
+ const CustomTypeSchema = v.object({
39
+ id: v.string(),
40
+ label: v.string(),
41
+ repeatable: v.boolean(),
42
+ status: v.boolean(),
43
+ format: v.string(),
44
+ json: v.record(v.string(), v.record(v.string(), v.unknown())),
45
+ });
46
+
47
+ export async function pageTypeAddFieldEmbed(): Promise<void> {
48
+ const {
49
+ values: { help, tab, label, placeholder, types, "no-types": noTypes },
50
+ positionals: [typeId, fieldId],
51
+ } = parseArgs({
52
+ args: process.argv.slice(5), // skip: node, script, "page-type", "add-field", "embed"
53
+ options: {
54
+ tab: { type: "string", short: "t" },
55
+ label: { type: "string", short: "l" },
56
+ placeholder: { type: "string", short: "p" },
57
+ types: { type: "string" },
58
+ "no-types": { type: "boolean" },
59
+ help: { type: "boolean", short: "h" },
60
+ },
61
+ allowPositionals: true,
62
+ });
63
+
64
+ if (help) {
65
+ console.info(HELP);
66
+ return;
67
+ }
68
+
69
+ if (!typeId) {
70
+ console.error("Missing required argument: type-id\n");
71
+ console.error("Usage: prismic page-type add-field embed <type-id> <field-id>");
72
+ process.exitCode = 1;
73
+ return;
74
+ }
75
+
76
+ if (!fieldId) {
77
+ console.error("Missing required argument: field-id\n");
78
+ console.error("Usage: prismic page-type add-field embed <type-id> <field-id>");
79
+ process.exitCode = 1;
80
+ return;
81
+ }
82
+
83
+ // Find the page type file
84
+ const projectRoot = await findUpward("package.json");
85
+ if (!projectRoot) {
86
+ console.error("Could not find project root (no package.json found)");
87
+ process.exitCode = 1;
88
+ return;
89
+ }
90
+
91
+ const modelPath = new URL(`customtypes/${typeId}/index.json`, projectRoot);
92
+
93
+ // Read and parse the model
94
+ let model: CustomType;
95
+ try {
96
+ const contents = await readFile(modelPath, "utf8");
97
+ const result = v.safeParse(CustomTypeSchema, JSON.parse(contents));
98
+ if (!result.success) {
99
+ console.error(`Invalid page type model: ${modelPath.href}`);
100
+ process.exitCode = 1;
101
+ return;
102
+ }
103
+ model = result.output as CustomType;
104
+ } catch (error) {
105
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
106
+ console.error(`Page type not found: ${typeId}\n`);
107
+ console.error(`Create it first with: prismic page-type create ${typeId}`);
108
+ process.exitCode = 1;
109
+ return;
110
+ }
111
+ if (error instanceof Error) {
112
+ console.error(`Failed to read page type: ${error.message}`);
113
+ } else {
114
+ console.error("Failed to read page type");
115
+ }
116
+ process.exitCode = 1;
117
+ return;
118
+ }
119
+
120
+ // Determine target tab
121
+ const existingTabs = Object.keys(model.json);
122
+ const targetTab = tab ?? existingTabs[0] ?? "Main";
123
+
124
+ // Initialize tab if it doesn't exist
125
+ if (!model.json[targetTab]) {
126
+ model.json[targetTab] = {};
127
+ }
128
+
129
+ // Check if field already exists in any tab
130
+ for (const [tabName, tabFields] of Object.entries(model.json)) {
131
+ if (tabFields[fieldId]) {
132
+ console.error(`Field "${fieldId}" already exists in tab "${tabName}"`);
133
+ process.exitCode = 1;
134
+ return;
135
+ }
136
+ }
137
+
138
+ // Build field definition
139
+ const fieldDefinition: Embed = {
140
+ type: "Embed",
141
+ config: {
142
+ label: label ?? humanReadable(fieldId),
143
+ ...(placeholder && { placeholder }),
144
+ },
145
+ };
146
+
147
+ // Add field to model
148
+ model.json[targetTab][fieldId] = fieldDefinition;
149
+
150
+ // Write updated model
151
+ try {
152
+ await writeFile(modelPath, stringify(model));
153
+ } catch (error) {
154
+ if (error instanceof Error) {
155
+ console.error(`Failed to update page type: ${error.message}`);
156
+ } else {
157
+ console.error("Failed to update page type");
158
+ }
159
+ process.exitCode = 1;
160
+ return;
161
+ }
162
+
163
+ console.info(`Added field "${fieldId}" (Embed) to "${targetTab}" tab in ${typeId}`);
164
+
165
+ if (!noTypes) {
166
+ try {
167
+ await buildTypes({ output: types });
168
+ console.info(`Updated types in ${types ?? "prismicio-types.d.ts"}`);
169
+ } catch (error) {
170
+ console.warn(`Could not generate types: ${error instanceof Error ? error.message : error}`);
171
+ }
172
+ }
173
+
174
+ console.info();
175
+ console.info("Next: Add more fields with `prismic page-type add-field`");
176
+ console.info(" Run `prismic status` when done to find next steps");
177
+ }
@@ -0,0 +1,174 @@
1
+ import type { CustomType, GeoPoint } from "@prismicio/types-internal/lib/customtypes";
2
+
3
+ import { readFile, writeFile } from "node:fs/promises";
4
+ import { parseArgs } from "node:util";
5
+ import * as v from "valibot";
6
+
7
+ import { buildTypes } from "./codegen-types";
8
+ import { findUpward } from "./lib/file";
9
+ import { stringify } from "./lib/json";
10
+ import { humanReadable } from "./lib/string";
11
+
12
+ const HELP = `
13
+ Add a geo-point (location) field to an existing page type.
14
+
15
+ USAGE
16
+ prismic page-type add-field geo-point <type-id> <field-id> [flags]
17
+
18
+ ARGUMENTS
19
+ type-id Page type identifier (required)
20
+ field-id Field identifier (required)
21
+
22
+ Types are generated by default after changes. Use --no-types to skip.
23
+
24
+ FLAGS
25
+ -t, --tab string Target tab (default: first existing tab, or "Main")
26
+ -l, --label string Display label for the field (inferred from field-id if omitted)
27
+ --types string Output file for generated types (default: "prismicio-types.d.ts")
28
+ --no-types Skip type generation
29
+ -h, --help Show help for command
30
+
31
+ EXAMPLES
32
+ prismic page-type add-field geo-point homepage location
33
+ prismic page-type add-field geo-point store address --tab "Details"
34
+ prismic page-type add-field geo-point event venue --label "Event Venue"
35
+ `.trim();
36
+
37
+ const CustomTypeSchema = v.object({
38
+ id: v.string(),
39
+ label: v.string(),
40
+ repeatable: v.boolean(),
41
+ status: v.boolean(),
42
+ format: v.string(),
43
+ json: v.record(v.string(), v.record(v.string(), v.unknown())),
44
+ });
45
+
46
+ export async function pageTypeAddFieldGeoPoint(): Promise<void> {
47
+ const {
48
+ values: { help, tab, label, types, "no-types": noTypes },
49
+ positionals: [typeId, fieldId],
50
+ } = parseArgs({
51
+ args: process.argv.slice(5), // skip: node, script, "page-type", "add-field", "geo-point"
52
+ options: {
53
+ tab: { type: "string", short: "t" },
54
+ label: { type: "string", short: "l" },
55
+ types: { type: "string" },
56
+ "no-types": { type: "boolean" },
57
+ help: { type: "boolean", short: "h" },
58
+ },
59
+ allowPositionals: true,
60
+ });
61
+
62
+ if (help) {
63
+ console.info(HELP);
64
+ return;
65
+ }
66
+
67
+ if (!typeId) {
68
+ console.error("Missing required argument: type-id\n");
69
+ console.error("Usage: prismic page-type add-field geo-point <type-id> <field-id>");
70
+ process.exitCode = 1;
71
+ return;
72
+ }
73
+
74
+ if (!fieldId) {
75
+ console.error("Missing required argument: field-id\n");
76
+ console.error("Usage: prismic page-type add-field geo-point <type-id> <field-id>");
77
+ process.exitCode = 1;
78
+ return;
79
+ }
80
+
81
+ // Find the page type file
82
+ const projectRoot = await findUpward("package.json");
83
+ if (!projectRoot) {
84
+ console.error("Could not find project root (no package.json found)");
85
+ process.exitCode = 1;
86
+ return;
87
+ }
88
+
89
+ const modelPath = new URL(`customtypes/${typeId}/index.json`, projectRoot);
90
+
91
+ // Read and parse the model
92
+ let model: CustomType;
93
+ try {
94
+ const contents = await readFile(modelPath, "utf8");
95
+ const result = v.safeParse(CustomTypeSchema, JSON.parse(contents));
96
+ if (!result.success) {
97
+ console.error(`Invalid page type model: ${modelPath.href}`);
98
+ process.exitCode = 1;
99
+ return;
100
+ }
101
+ model = result.output as CustomType;
102
+ } catch (error) {
103
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
104
+ console.error(`Page type not found: ${typeId}\n`);
105
+ console.error(`Create it first with: prismic page-type create ${typeId}`);
106
+ process.exitCode = 1;
107
+ return;
108
+ }
109
+ if (error instanceof Error) {
110
+ console.error(`Failed to read page type: ${error.message}`);
111
+ } else {
112
+ console.error("Failed to read page type");
113
+ }
114
+ process.exitCode = 1;
115
+ return;
116
+ }
117
+
118
+ // Determine target tab
119
+ const existingTabs = Object.keys(model.json);
120
+ const targetTab = tab ?? existingTabs[0] ?? "Main";
121
+
122
+ // Initialize tab if it doesn't exist
123
+ if (!model.json[targetTab]) {
124
+ model.json[targetTab] = {};
125
+ }
126
+
127
+ // Check if field already exists in any tab
128
+ for (const [tabName, tabFields] of Object.entries(model.json)) {
129
+ if (tabFields[fieldId]) {
130
+ console.error(`Field "${fieldId}" already exists in tab "${tabName}"`);
131
+ process.exitCode = 1;
132
+ return;
133
+ }
134
+ }
135
+
136
+ // Build field definition
137
+ const fieldDefinition: GeoPoint = {
138
+ type: "GeoPoint",
139
+ config: {
140
+ label: label ?? humanReadable(fieldId),
141
+ },
142
+ };
143
+
144
+ // Add field to model
145
+ model.json[targetTab][fieldId] = fieldDefinition;
146
+
147
+ // Write updated model
148
+ try {
149
+ await writeFile(modelPath, stringify(model));
150
+ } catch (error) {
151
+ if (error instanceof Error) {
152
+ console.error(`Failed to update page type: ${error.message}`);
153
+ } else {
154
+ console.error("Failed to update page type");
155
+ }
156
+ process.exitCode = 1;
157
+ return;
158
+ }
159
+
160
+ console.info(`Added field "${fieldId}" (GeoPoint) to "${targetTab}" tab in ${typeId}`);
161
+
162
+ if (!noTypes) {
163
+ try {
164
+ await buildTypes({ output: types });
165
+ console.info(`Updated types in ${types ?? "prismicio-types.d.ts"}`);
166
+ } catch (error) {
167
+ console.warn(`Could not generate types: ${error instanceof Error ? error.message : error}`);
168
+ }
169
+ }
170
+
171
+ console.info();
172
+ console.info("Next: Add more fields with `prismic page-type add-field`");
173
+ console.info(" Run `prismic status` when done to find next steps");
174
+ }