@angeloashmore/prismic-cli-poc 0.0.0-canary.1143872

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 (139) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +98 -0
  3. package/dist/index.mjs +2508 -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 +222 -0
  8. package/src/custom-type-add-field-color.ts +205 -0
  9. package/src/custom-type-add-field-date.ts +208 -0
  10. package/src/custom-type-add-field-embed.ts +205 -0
  11. package/src/custom-type-add-field-geo-point.ts +202 -0
  12. package/src/custom-type-add-field-group.ts +179 -0
  13. package/src/custom-type-add-field-image.ts +205 -0
  14. package/src/custom-type-add-field-key-text.ts +205 -0
  15. package/src/custom-type-add-field-link.ts +228 -0
  16. package/src/custom-type-add-field-number.ts +237 -0
  17. package/src/custom-type-add-field-rich-text.ts +229 -0
  18. package/src/custom-type-add-field-select.ts +211 -0
  19. package/src/custom-type-add-field-timestamp.ts +208 -0
  20. package/src/custom-type-add-field-uid.ts +188 -0
  21. package/src/custom-type-add-field.ts +116 -0
  22. package/src/custom-type-connect-slice.ts +214 -0
  23. package/src/custom-type-create.ts +112 -0
  24. package/src/custom-type-disconnect-slice.ts +171 -0
  25. package/src/custom-type-list.ts +110 -0
  26. package/src/custom-type-remove-field.ts +171 -0
  27. package/src/custom-type-remove.ts +138 -0
  28. package/src/custom-type-set-name.ts +138 -0
  29. package/src/custom-type-view.ts +118 -0
  30. package/src/custom-type.ts +85 -0
  31. package/src/docs-fetch.ts +146 -0
  32. package/src/docs-list.ts +131 -0
  33. package/src/docs.ts +54 -0
  34. package/src/index.ts +132 -0
  35. package/src/init.ts +64 -0
  36. package/src/lib/auth.ts +83 -0
  37. package/src/lib/config.ts +111 -0
  38. package/src/lib/custom-types-api.ts +438 -0
  39. package/src/lib/field-path.ts +81 -0
  40. package/src/lib/file.ts +49 -0
  41. package/src/lib/framework.ts +143 -0
  42. package/src/lib/json.ts +3 -0
  43. package/src/lib/request.ts +116 -0
  44. package/src/lib/slice.ts +115 -0
  45. package/src/lib/string.ts +6 -0
  46. package/src/lib/url.ts +25 -0
  47. package/src/locale-add.ts +116 -0
  48. package/src/locale-list.ts +107 -0
  49. package/src/locale-remove.ts +88 -0
  50. package/src/locale-set-default.ts +131 -0
  51. package/src/locale.ts +60 -0
  52. package/src/login.ts +152 -0
  53. package/src/logout.ts +36 -0
  54. package/src/page-type-add-field-boolean.ts +238 -0
  55. package/src/page-type-add-field-color.ts +224 -0
  56. package/src/page-type-add-field-date.ts +227 -0
  57. package/src/page-type-add-field-embed.ts +224 -0
  58. package/src/page-type-add-field-geo-point.ts +221 -0
  59. package/src/page-type-add-field-group.ts +198 -0
  60. package/src/page-type-add-field-image.ts +224 -0
  61. package/src/page-type-add-field-key-text.ts +224 -0
  62. package/src/page-type-add-field-link.ts +247 -0
  63. package/src/page-type-add-field-number.ts +256 -0
  64. package/src/page-type-add-field-rich-text.ts +248 -0
  65. package/src/page-type-add-field-select.ts +230 -0
  66. package/src/page-type-add-field-timestamp.ts +227 -0
  67. package/src/page-type-add-field-uid.ts +207 -0
  68. package/src/page-type-add-field.ts +116 -0
  69. package/src/page-type-connect-slice.ts +214 -0
  70. package/src/page-type-create.ts +161 -0
  71. package/src/page-type-disconnect-slice.ts +171 -0
  72. package/src/page-type-list.ts +109 -0
  73. package/src/page-type-remove-field.ts +171 -0
  74. package/src/page-type-remove.ts +138 -0
  75. package/src/page-type-set-name.ts +138 -0
  76. package/src/page-type-set-repeatable.ts +147 -0
  77. package/src/page-type-view.ts +118 -0
  78. package/src/page-type.ts +90 -0
  79. package/src/preview-add.ts +126 -0
  80. package/src/preview-get-simulator.ts +104 -0
  81. package/src/preview-list.ts +106 -0
  82. package/src/preview-remove-simulator.ts +80 -0
  83. package/src/preview-remove.ts +109 -0
  84. package/src/preview-set-name.ts +137 -0
  85. package/src/preview-set-simulator.ts +116 -0
  86. package/src/preview.ts +75 -0
  87. package/src/pull.ts +242 -0
  88. package/src/push.ts +405 -0
  89. package/src/repo-create.ts +195 -0
  90. package/src/repo-get-access.ts +86 -0
  91. package/src/repo-list.ts +100 -0
  92. package/src/repo-set-access.ts +100 -0
  93. package/src/repo-set-name.ts +102 -0
  94. package/src/repo-view.ts +113 -0
  95. package/src/repo.ts +70 -0
  96. package/src/slice-add-field-boolean.ts +240 -0
  97. package/src/slice-add-field-color.ts +226 -0
  98. package/src/slice-add-field-date.ts +226 -0
  99. package/src/slice-add-field-embed.ts +226 -0
  100. package/src/slice-add-field-geo-point.ts +223 -0
  101. package/src/slice-add-field-group.ts +191 -0
  102. package/src/slice-add-field-image.ts +223 -0
  103. package/src/slice-add-field-key-text.ts +226 -0
  104. package/src/slice-add-field-link.ts +245 -0
  105. package/src/slice-add-field-number.ts +226 -0
  106. package/src/slice-add-field-rich-text.ts +250 -0
  107. package/src/slice-add-field-select.ts +232 -0
  108. package/src/slice-add-field-timestamp.ts +226 -0
  109. package/src/slice-add-field.ts +111 -0
  110. package/src/slice-add-variation.ts +139 -0
  111. package/src/slice-create.ts +203 -0
  112. package/src/slice-list-variations.ts +67 -0
  113. package/src/slice-list.ts +88 -0
  114. package/src/slice-remove-field.ts +122 -0
  115. package/src/slice-remove-variation.ts +112 -0
  116. package/src/slice-remove.ts +91 -0
  117. package/src/slice-rename.ts +122 -0
  118. package/src/slice-set-screenshot.ts +235 -0
  119. package/src/slice-view.ts +80 -0
  120. package/src/slice.ts +95 -0
  121. package/src/status.ts +873 -0
  122. package/src/token-create.ts +203 -0
  123. package/src/token-delete.ts +182 -0
  124. package/src/token-list.ts +223 -0
  125. package/src/token-set-name.ts +193 -0
  126. package/src/token.ts +60 -0
  127. package/src/webhook-add-header.ts +118 -0
  128. package/src/webhook-create.ts +152 -0
  129. package/src/webhook-disable.ts +109 -0
  130. package/src/webhook-enable.ts +132 -0
  131. package/src/webhook-list.ts +93 -0
  132. package/src/webhook-remove-header.ts +117 -0
  133. package/src/webhook-remove.ts +106 -0
  134. package/src/webhook-set-triggers.ts +148 -0
  135. package/src/webhook-status.ts +90 -0
  136. package/src/webhook-test.ts +106 -0
  137. package/src/webhook-view.ts +147 -0
  138. package/src/webhook.ts +95 -0
  139. package/src/whoami.ts +62 -0
@@ -0,0 +1,109 @@
1
+ import { readdir, readFile } from "node:fs/promises";
2
+ import { parseArgs } from "node:util";
3
+ import * as v from "valibot";
4
+
5
+ import { findUpward } from "./lib/file";
6
+
7
+ const HELP = `
8
+ List all page types in a Prismic project.
9
+
10
+ USAGE
11
+ prismic page-type list [flags]
12
+
13
+ FLAGS
14
+ --json Output as JSON
15
+ -h, --help Show help for command
16
+
17
+ EXAMPLES
18
+ prismic page-type list
19
+ prismic page-type list --json
20
+ `.trim();
21
+
22
+ const CustomTypeSchema = v.object({
23
+ id: v.string(),
24
+ label: v.string(),
25
+ repeatable: v.boolean(),
26
+ status: v.boolean(),
27
+ format: v.optional(v.string()),
28
+ json: v.record(v.string(), v.record(v.string(), v.unknown())),
29
+ });
30
+
31
+ export async function pageTypeList(): Promise<void> {
32
+ const {
33
+ values: { help, json },
34
+ } = parseArgs({
35
+ args: process.argv.slice(4), // skip: node, script, "page-type", "list"
36
+ options: {
37
+ json: { type: "boolean" },
38
+ help: { type: "boolean", short: "h" },
39
+ },
40
+ allowPositionals: true,
41
+ });
42
+
43
+ if (help) {
44
+ console.info(HELP);
45
+ return;
46
+ }
47
+
48
+ const projectRoot = await findUpward("package.json");
49
+ if (!projectRoot) {
50
+ console.error("Could not find project root (no package.json found)");
51
+ process.exitCode = 1;
52
+ return;
53
+ }
54
+
55
+ const customTypesDirectory = new URL("customtypes/", projectRoot);
56
+
57
+ let entries: string[];
58
+ try {
59
+ entries = (await readdir(customTypesDirectory, {
60
+ withFileTypes: false,
61
+ })) as unknown as string[];
62
+ } catch {
63
+ if (json) {
64
+ console.info(JSON.stringify([]));
65
+ } else {
66
+ console.info("No page types found.");
67
+ }
68
+ return;
69
+ }
70
+
71
+ const pageTypes: { id: string; label: string; repeatable: boolean }[] = [];
72
+
73
+ for (const entry of entries) {
74
+ const modelPath = new URL(`${entry}/index.json`, customTypesDirectory);
75
+ try {
76
+ const contents = await readFile(modelPath, "utf8");
77
+ const parsed = JSON.parse(contents);
78
+ const result = v.safeParse(CustomTypeSchema, parsed);
79
+ if (result.success && result.output.format === "page") {
80
+ pageTypes.push({
81
+ id: result.output.id,
82
+ label: result.output.label,
83
+ repeatable: result.output.repeatable,
84
+ });
85
+ }
86
+ } catch {
87
+ // Skip directories without valid index.json
88
+ }
89
+ }
90
+
91
+ if (pageTypes.length === 0) {
92
+ if (json) {
93
+ console.info(JSON.stringify([]));
94
+ } else {
95
+ console.info("No page types found.");
96
+ }
97
+ return;
98
+ }
99
+
100
+ if (json) {
101
+ console.info(JSON.stringify(pageTypes, null, 2));
102
+ } else {
103
+ console.info("ID\tLABEL\tTYPE");
104
+ for (const pageType of pageTypes) {
105
+ const typeLabel = pageType.repeatable ? "repeatable" : "singleton";
106
+ console.info(`${pageType.id}\t${pageType.label}\t${typeLabel}`);
107
+ }
108
+ }
109
+ }
@@ -0,0 +1,171 @@
1
+ import type { 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
+
11
+ const HELP = `
12
+ Remove a field from a page type.
13
+
14
+ USAGE
15
+ prismic page-type remove-field <type-id> <field-id> [flags]
16
+
17
+ ARGUMENTS
18
+ type-id Page type identifier (required)
19
+ field-id Field identifier (required)
20
+
21
+ FLAGS
22
+ --tab string Specific tab (searches all tabs if not specified)
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 page-type remove-field homepage title
28
+ prismic page-type remove-field homepage meta_title --tab "SEO & Metadata"
29
+ `.trim();
30
+
31
+ const CustomTypeSchema = v.object({
32
+ id: v.string(),
33
+ label: v.string(),
34
+ repeatable: v.boolean(),
35
+ status: v.boolean(),
36
+ format: v.optional(v.string()),
37
+ json: v.record(v.string(), v.record(v.string(), v.unknown())),
38
+ });
39
+
40
+ export async function pageTypeRemoveField(): Promise<void> {
41
+ const {
42
+ values: { help, tab, types },
43
+ positionals: [typeId, fieldId],
44
+ } = parseArgs({
45
+ args: process.argv.slice(4), // skip: node, script, "page-type", "remove-field"
46
+ options: {
47
+ tab: { type: "string" },
48
+ types: { type: "string" },
49
+ help: { type: "boolean", short: "h" },
50
+ },
51
+ allowPositionals: true,
52
+ });
53
+
54
+ if (help) {
55
+ console.info(HELP);
56
+ return;
57
+ }
58
+
59
+ if (!typeId) {
60
+ console.error("Missing required argument: type-id\n");
61
+ console.error("Usage: prismic page-type remove-field <type-id> <field-id>");
62
+ process.exitCode = 1;
63
+ return;
64
+ }
65
+
66
+ if (!fieldId) {
67
+ console.error("Missing required argument: field-id\n");
68
+ console.error("Usage: prismic page-type remove-field <type-id> <field-id>");
69
+ process.exitCode = 1;
70
+ return;
71
+ }
72
+
73
+ const projectRoot = await findUpward("package.json");
74
+ if (!projectRoot) {
75
+ console.error("Could not find project root (no package.json found)");
76
+ process.exitCode = 1;
77
+ return;
78
+ }
79
+
80
+ const modelPath = new URL(`customtypes/${typeId}/index.json`, projectRoot);
81
+
82
+ // Read and parse the model
83
+ let model: CustomType;
84
+ try {
85
+ const contents = await readFile(modelPath, "utf8");
86
+ const result = v.safeParse(CustomTypeSchema, JSON.parse(contents));
87
+ if (!result.success) {
88
+ console.error(`Invalid page type model: ${modelPath.href}`);
89
+ process.exitCode = 1;
90
+ return;
91
+ }
92
+ model = result.output as CustomType;
93
+ } catch (error) {
94
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
95
+ console.error(`Page type not found: ${typeId}\n`);
96
+ console.error(`Create it first with: prismic page-type create ${typeId}`);
97
+ process.exitCode = 1;
98
+ return;
99
+ }
100
+ if (error instanceof Error) {
101
+ console.error(`Failed to read page type: ${error.message}`);
102
+ } else {
103
+ console.error("Failed to read page type");
104
+ }
105
+ process.exitCode = 1;
106
+ return;
107
+ }
108
+
109
+ // Check if this is actually a page type
110
+ if (model.format !== "page") {
111
+ console.error(`"${typeId}" is not a page type (format: ${model.format ?? "custom"})`);
112
+ process.exitCode = 1;
113
+ return;
114
+ }
115
+
116
+ // Find and remove the field
117
+ let foundTab: string | undefined;
118
+
119
+ if (tab) {
120
+ // Look in specific tab
121
+ if (!model.json[tab]) {
122
+ console.error(`Tab "${tab}" not found in page type "${typeId}"`);
123
+ console.error(`Available tabs: ${Object.keys(model.json).join(", ")}`);
124
+ process.exitCode = 1;
125
+ return;
126
+ }
127
+ if (!(fieldId in model.json[tab])) {
128
+ console.error(`Field "${fieldId}" not found in tab "${tab}"`);
129
+ process.exitCode = 1;
130
+ return;
131
+ }
132
+ delete model.json[tab][fieldId];
133
+ foundTab = tab;
134
+ } else {
135
+ // Search all tabs
136
+ for (const [tabName, tabFields] of Object.entries(model.json)) {
137
+ if (fieldId in tabFields) {
138
+ delete tabFields[fieldId];
139
+ foundTab = tabName;
140
+ break;
141
+ }
142
+ }
143
+ if (!foundTab) {
144
+ console.error(`Field "${fieldId}" not found in any tab of page type "${typeId}"`);
145
+ process.exitCode = 1;
146
+ return;
147
+ }
148
+ }
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(`Removed field "${fieldId}" from tab "${foundTab}" in page type "${typeId}"`);
164
+
165
+ try {
166
+ await buildTypes({ output: types });
167
+ console.info(`Updated types in ${types ?? "prismicio-types.d.ts"}`);
168
+ } catch (error) {
169
+ console.warn(`Could not generate types: ${error instanceof Error ? error.message : error}`);
170
+ }
171
+ }
@@ -0,0 +1,138 @@
1
+ import type { CustomType } from "@prismicio/types-internal/lib/customtypes";
2
+
3
+ import { readFile, rm } 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
+
10
+ const HELP = `
11
+ Remove a page type from the project.
12
+
13
+ USAGE
14
+ prismic page-type remove <type-id> [flags]
15
+
16
+ ARGUMENTS
17
+ type-id Page type identifier (required)
18
+
19
+ FLAGS
20
+ -y Confirm removal
21
+ --types string Output file for generated types (default: "prismicio-types.d.ts")
22
+ -h, --help Show help for command
23
+
24
+ EXAMPLES
25
+ prismic page-type remove homepage
26
+ prismic page-type remove homepage -y
27
+ `.trim();
28
+
29
+ const CustomTypeSchema = v.object({
30
+ id: v.string(),
31
+ label: v.string(),
32
+ repeatable: v.boolean(),
33
+ status: v.boolean(),
34
+ format: v.optional(v.string()),
35
+ json: v.record(v.string(), v.record(v.string(), v.unknown())),
36
+ });
37
+
38
+ export async function pageTypeRemove(): Promise<void> {
39
+ const {
40
+ values: { help, y, types },
41
+ positionals: [typeId],
42
+ } = parseArgs({
43
+ args: process.argv.slice(4), // skip: node, script, "page-type", "remove"
44
+ options: {
45
+ y: { type: "boolean", short: "y" },
46
+ types: { type: "string" },
47
+ help: { type: "boolean", short: "h" },
48
+ },
49
+ allowPositionals: true,
50
+ });
51
+
52
+ if (help) {
53
+ console.info(HELP);
54
+ return;
55
+ }
56
+
57
+ if (!typeId) {
58
+ console.error("Missing required argument: type-id\n");
59
+ console.error("Usage: prismic page-type remove <type-id>");
60
+ process.exitCode = 1;
61
+ return;
62
+ }
63
+
64
+ const projectRoot = await findUpward("package.json");
65
+ if (!projectRoot) {
66
+ console.error("Could not find project root (no package.json found)");
67
+ process.exitCode = 1;
68
+ return;
69
+ }
70
+
71
+ const typeDirectory = new URL(`customtypes/${typeId}/`, projectRoot);
72
+ const modelPath = new URL("index.json", typeDirectory);
73
+
74
+ // Verify the page type exists and is actually a page type
75
+ let model: CustomType;
76
+ try {
77
+ const contents = await readFile(modelPath, "utf8");
78
+ const result = v.safeParse(CustomTypeSchema, JSON.parse(contents));
79
+ if (!result.success) {
80
+ console.error(`Invalid page type model: ${modelPath.href}`);
81
+ process.exitCode = 1;
82
+ return;
83
+ }
84
+ model = result.output as CustomType;
85
+ } catch (error) {
86
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
87
+ console.error(`Page type not found: ${typeId}`);
88
+ process.exitCode = 1;
89
+ return;
90
+ }
91
+ if (error instanceof Error) {
92
+ console.error(`Failed to read page type: ${error.message}`);
93
+ } else {
94
+ console.error("Failed to read page type");
95
+ }
96
+ process.exitCode = 1;
97
+ return;
98
+ }
99
+
100
+ // Check if this is actually a page type
101
+ if (model.format !== "page") {
102
+ console.error(`"${typeId}" is not a page type (format: ${model.format ?? "custom"})`);
103
+ process.exitCode = 1;
104
+ return;
105
+ }
106
+
107
+ // Require -y flag to confirm deletion
108
+ if (!y) {
109
+ console.error(
110
+ `Refusing to remove page type "${typeId}" (this will delete the entire directory).`,
111
+ );
112
+ console.error("Re-run with -y to confirm.");
113
+ process.exitCode = 1;
114
+ return;
115
+ }
116
+
117
+ // Delete the page type directory
118
+ try {
119
+ await rm(typeDirectory, { recursive: true });
120
+ } catch (error) {
121
+ if (error instanceof Error) {
122
+ console.error(`Failed to remove page type: ${error.message}`);
123
+ } else {
124
+ console.error("Failed to remove page type");
125
+ }
126
+ process.exitCode = 1;
127
+ return;
128
+ }
129
+
130
+ console.info(`Removed page type "${typeId}"`);
131
+
132
+ try {
133
+ await buildTypes({ output: types });
134
+ console.info(`Updated types in ${types ?? "prismicio-types.d.ts"}`);
135
+ } catch (error) {
136
+ console.warn(`Could not generate types: ${error instanceof Error ? error.message : error}`);
137
+ }
138
+ }
@@ -0,0 +1,138 @@
1
+ import type { 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
+
11
+ const HELP = `
12
+ Change a page type's display name (label).
13
+
14
+ USAGE
15
+ prismic page-type set-name <type-id> <new-name> [flags]
16
+
17
+ ARGUMENTS
18
+ type-id Page type identifier (required)
19
+ new-name New display name (required)
20
+
21
+ FLAGS
22
+ --types string Output file for generated types (default: "prismicio-types.d.ts")
23
+ -h, --help Show help for command
24
+
25
+ EXAMPLES
26
+ prismic page-type set-name homepage "Home Page"
27
+ prismic page-type set-name blog_post "Blog Post"
28
+ `.trim();
29
+
30
+ const CustomTypeSchema = v.object({
31
+ id: v.string(),
32
+ label: v.string(),
33
+ repeatable: v.boolean(),
34
+ status: v.boolean(),
35
+ format: v.optional(v.string()),
36
+ json: v.record(v.string(), v.record(v.string(), v.unknown())),
37
+ });
38
+
39
+ export async function pageTypeSetName(): Promise<void> {
40
+ const {
41
+ values: { help, types },
42
+ positionals: [typeId, newName],
43
+ } = parseArgs({
44
+ args: process.argv.slice(4), // skip: node, script, "page-type", "set-name"
45
+ options: {
46
+ types: { type: "string" },
47
+ help: { type: "boolean", short: "h" },
48
+ },
49
+ allowPositionals: true,
50
+ });
51
+
52
+ if (help) {
53
+ console.info(HELP);
54
+ return;
55
+ }
56
+
57
+ if (!typeId) {
58
+ console.error("Missing required argument: type-id\n");
59
+ console.error("Usage: prismic page-type set-name <type-id> <new-name>");
60
+ process.exitCode = 1;
61
+ return;
62
+ }
63
+
64
+ if (!newName) {
65
+ console.error("Missing required argument: new-name\n");
66
+ console.error("Usage: prismic page-type set-name <type-id> <new-name>");
67
+ process.exitCode = 1;
68
+ return;
69
+ }
70
+
71
+ const projectRoot = await findUpward("package.json");
72
+ if (!projectRoot) {
73
+ console.error("Could not find project root (no package.json found)");
74
+ process.exitCode = 1;
75
+ return;
76
+ }
77
+
78
+ const modelPath = new URL(`customtypes/${typeId}/index.json`, projectRoot);
79
+
80
+ // Read and parse the model
81
+ let model: CustomType;
82
+ try {
83
+ const contents = await readFile(modelPath, "utf8");
84
+ const result = v.safeParse(CustomTypeSchema, JSON.parse(contents));
85
+ if (!result.success) {
86
+ console.error(`Invalid page type model: ${modelPath.href}`);
87
+ process.exitCode = 1;
88
+ return;
89
+ }
90
+ model = result.output as CustomType;
91
+ } catch (error) {
92
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
93
+ console.error(`Page type not found: ${typeId}\n`);
94
+ console.error(`Create it first with: prismic page-type create ${typeId}`);
95
+ process.exitCode = 1;
96
+ return;
97
+ }
98
+ if (error instanceof Error) {
99
+ console.error(`Failed to read page type: ${error.message}`);
100
+ } else {
101
+ console.error("Failed to read page type");
102
+ }
103
+ process.exitCode = 1;
104
+ return;
105
+ }
106
+
107
+ // Check if this is actually a page type
108
+ if (model.format !== "page") {
109
+ console.error(`"${typeId}" is not a page type (format: ${model.format ?? "custom"})`);
110
+ process.exitCode = 1;
111
+ return;
112
+ }
113
+
114
+ // Update the model
115
+ model.label = newName;
116
+
117
+ // Write updated model
118
+ try {
119
+ await writeFile(modelPath, stringify(model));
120
+ } catch (error) {
121
+ if (error instanceof Error) {
122
+ console.error(`Failed to update page type: ${error.message}`);
123
+ } else {
124
+ console.error("Failed to update page type");
125
+ }
126
+ process.exitCode = 1;
127
+ return;
128
+ }
129
+
130
+ console.info(`Renamed page type "${typeId}" to "${newName}"`);
131
+
132
+ try {
133
+ await buildTypes({ output: types });
134
+ console.info(`Updated types in ${types ?? "prismicio-types.d.ts"}`);
135
+ } catch (error) {
136
+ console.warn(`Could not generate types: ${error instanceof Error ? error.message : error}`);
137
+ }
138
+ }
@@ -0,0 +1,147 @@
1
+ import type { 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
+
11
+ const HELP = `
12
+ Set whether a page type is repeatable.
13
+
14
+ USAGE
15
+ prismic page-type set-repeatable <type-id> <true|false> [flags]
16
+
17
+ ARGUMENTS
18
+ type-id Page type identifier (required)
19
+ true|false Repeatable value (required)
20
+
21
+ FLAGS
22
+ --types string Output file for generated types (default: "prismicio-types.d.ts")
23
+ -h, --help Show help for command
24
+
25
+ EXAMPLES
26
+ prismic page-type set-repeatable homepage true
27
+ prismic page-type set-repeatable settings false
28
+ `.trim();
29
+
30
+ const CustomTypeSchema = v.object({
31
+ id: v.string(),
32
+ label: v.string(),
33
+ repeatable: v.boolean(),
34
+ status: v.boolean(),
35
+ format: v.optional(v.string()),
36
+ json: v.record(v.string(), v.record(v.string(), v.unknown())),
37
+ });
38
+
39
+ export async function pageTypeSetRepeatable(): Promise<void> {
40
+ const {
41
+ values: { help, types },
42
+ positionals: [typeId, repeatableValue],
43
+ } = parseArgs({
44
+ args: process.argv.slice(4), // skip: node, script, "page-type", "set-repeatable"
45
+ options: {
46
+ types: { type: "string" },
47
+ help: { type: "boolean", short: "h" },
48
+ },
49
+ allowPositionals: true,
50
+ });
51
+
52
+ if (help) {
53
+ console.info(HELP);
54
+ return;
55
+ }
56
+
57
+ if (!typeId) {
58
+ console.error("Missing required argument: type-id\n");
59
+ console.error("Usage: prismic page-type set-repeatable <type-id> <true|false>");
60
+ process.exitCode = 1;
61
+ return;
62
+ }
63
+
64
+ if (!repeatableValue) {
65
+ console.error("Missing required argument: true|false\n");
66
+ console.error("Usage: prismic page-type set-repeatable <type-id> <true|false>");
67
+ process.exitCode = 1;
68
+ return;
69
+ }
70
+
71
+ if (repeatableValue !== "true" && repeatableValue !== "false") {
72
+ console.error(`Invalid value: "${repeatableValue}". Must be "true" or "false".`);
73
+ process.exitCode = 1;
74
+ return;
75
+ }
76
+
77
+ const repeatable = repeatableValue === "true";
78
+
79
+ const projectRoot = await findUpward("package.json");
80
+ if (!projectRoot) {
81
+ console.error("Could not find project root (no package.json found)");
82
+ process.exitCode = 1;
83
+ return;
84
+ }
85
+
86
+ const modelPath = new URL(`customtypes/${typeId}/index.json`, projectRoot);
87
+
88
+ // Read and parse the model
89
+ let model: CustomType;
90
+ try {
91
+ const contents = await readFile(modelPath, "utf8");
92
+ const result = v.safeParse(CustomTypeSchema, JSON.parse(contents));
93
+ if (!result.success) {
94
+ console.error(`Invalid page type model: ${modelPath.href}`);
95
+ process.exitCode = 1;
96
+ return;
97
+ }
98
+ model = result.output as CustomType;
99
+ } catch (error) {
100
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
101
+ console.error(`Page type not found: ${typeId}\n`);
102
+ console.error(`Create it first with: prismic page-type create ${typeId}`);
103
+ process.exitCode = 1;
104
+ return;
105
+ }
106
+ if (error instanceof Error) {
107
+ console.error(`Failed to read page type: ${error.message}`);
108
+ } else {
109
+ console.error("Failed to read page type");
110
+ }
111
+ process.exitCode = 1;
112
+ return;
113
+ }
114
+
115
+ // Check if this is actually a page type
116
+ if (model.format !== "page") {
117
+ console.error(`"${typeId}" is not a page type (format: ${model.format ?? "custom"})`);
118
+ process.exitCode = 1;
119
+ return;
120
+ }
121
+
122
+ // Update the model
123
+ model.repeatable = repeatable;
124
+
125
+ // Write updated model
126
+ try {
127
+ await writeFile(modelPath, stringify(model));
128
+ } catch (error) {
129
+ if (error instanceof Error) {
130
+ console.error(`Failed to update page type: ${error.message}`);
131
+ } else {
132
+ console.error("Failed to update page type");
133
+ }
134
+ process.exitCode = 1;
135
+ return;
136
+ }
137
+
138
+ const typeLabel = repeatable ? "repeatable" : "singleton";
139
+ console.info(`Set page type "${typeId}" to ${typeLabel}`);
140
+
141
+ try {
142
+ await buildTypes({ output: types });
143
+ console.info(`Updated types in ${types ?? "prismicio-types.d.ts"}`);
144
+ } catch (error) {
145
+ console.warn(`Could not generate types: ${error instanceof Error ? error.message : error}`);
146
+ }
147
+ }