@angeloashmore/prismic-cli-poc 0.0.0-canary.2ff9563

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 (119) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +98 -0
  3. package/dist/index.mjs +1996 -0
  4. package/package.json +52 -0
  5. package/src/custom-type-add-field-boolean.ts +171 -0
  6. package/src/custom-type-add-field-color.ts +158 -0
  7. package/src/custom-type-add-field-date.ts +161 -0
  8. package/src/custom-type-add-field-embed.ts +158 -0
  9. package/src/custom-type-add-field-geo-point.ts +155 -0
  10. package/src/custom-type-add-field-image.ts +158 -0
  11. package/src/custom-type-add-field-key-text.ts +158 -0
  12. package/src/custom-type-add-field-link.ts +180 -0
  13. package/src/custom-type-add-field-number.ts +190 -0
  14. package/src/custom-type-add-field-rich-text.ts +181 -0
  15. package/src/custom-type-add-field-select.ts +164 -0
  16. package/src/custom-type-add-field-timestamp.ts +161 -0
  17. package/src/custom-type-add-field-uid.ts +158 -0
  18. package/src/custom-type-add-field.ts +111 -0
  19. package/src/custom-type-connect-slice.ts +221 -0
  20. package/src/custom-type-create.ts +92 -0
  21. package/src/custom-type-disconnect-slice.ts +179 -0
  22. package/src/custom-type-list.ts +110 -0
  23. package/src/custom-type-remove-field.ts +161 -0
  24. package/src/custom-type-remove.ts +126 -0
  25. package/src/custom-type-set-name.ts +128 -0
  26. package/src/custom-type-view.ts +118 -0
  27. package/src/custom-type.ts +85 -0
  28. package/src/index.ts +100 -0
  29. package/src/init.ts +62 -0
  30. package/src/lib/auth.ts +60 -0
  31. package/src/lib/config.ts +111 -0
  32. package/src/lib/file.ts +49 -0
  33. package/src/lib/json.ts +3 -0
  34. package/src/lib/request.ts +116 -0
  35. package/src/lib/slice.ts +112 -0
  36. package/src/lib/url.ts +25 -0
  37. package/src/locale-add.ts +116 -0
  38. package/src/locale-list.ts +107 -0
  39. package/src/locale-remove.ts +88 -0
  40. package/src/locale-set-default.ts +131 -0
  41. package/src/locale.ts +60 -0
  42. package/src/login.ts +143 -0
  43. package/src/logout.ts +36 -0
  44. package/src/page-type-add-field-boolean.ts +171 -0
  45. package/src/page-type-add-field-color.ts +158 -0
  46. package/src/page-type-add-field-date.ts +161 -0
  47. package/src/page-type-add-field-embed.ts +158 -0
  48. package/src/page-type-add-field-geo-point.ts +155 -0
  49. package/src/page-type-add-field-image.ts +158 -0
  50. package/src/page-type-add-field-key-text.ts +158 -0
  51. package/src/page-type-add-field-link.ts +180 -0
  52. package/src/page-type-add-field-number.ts +190 -0
  53. package/src/page-type-add-field-rich-text.ts +181 -0
  54. package/src/page-type-add-field-select.ts +164 -0
  55. package/src/page-type-add-field-timestamp.ts +161 -0
  56. package/src/page-type-add-field-uid.ts +158 -0
  57. package/src/page-type-add-field.ts +111 -0
  58. package/src/page-type-connect-slice.ts +221 -0
  59. package/src/page-type-create.ts +93 -0
  60. package/src/page-type-disconnect-slice.ts +179 -0
  61. package/src/page-type-list.ts +109 -0
  62. package/src/page-type-remove-field.ts +161 -0
  63. package/src/page-type-remove.ts +126 -0
  64. package/src/page-type-set-name.ts +128 -0
  65. package/src/page-type-set-repeatable.ts +137 -0
  66. package/src/page-type-view.ts +118 -0
  67. package/src/page-type.ts +90 -0
  68. package/src/preview-add.ts +126 -0
  69. package/src/preview-list.ts +106 -0
  70. package/src/preview-remove.ts +109 -0
  71. package/src/preview-set-name.ts +137 -0
  72. package/src/preview.ts +60 -0
  73. package/src/repo-create.ts +136 -0
  74. package/src/repo-list.ts +100 -0
  75. package/src/repo-set-name.ts +102 -0
  76. package/src/repo-view.ts +113 -0
  77. package/src/repo.ts +60 -0
  78. package/src/slice-add-field-boolean.ts +150 -0
  79. package/src/slice-add-field-color.ts +137 -0
  80. package/src/slice-add-field-date.ts +137 -0
  81. package/src/slice-add-field-embed.ts +137 -0
  82. package/src/slice-add-field-geo-point.ts +134 -0
  83. package/src/slice-add-field-image.ts +134 -0
  84. package/src/slice-add-field-key-text.ts +137 -0
  85. package/src/slice-add-field-link.ts +155 -0
  86. package/src/slice-add-field-number.ts +137 -0
  87. package/src/slice-add-field-rich-text.ts +160 -0
  88. package/src/slice-add-field-select.ts +143 -0
  89. package/src/slice-add-field-timestamp.ts +137 -0
  90. package/src/slice-add-field.ts +106 -0
  91. package/src/slice-add-variation.ts +137 -0
  92. package/src/slice-create.ts +129 -0
  93. package/src/slice-list-variations.ts +67 -0
  94. package/src/slice-list.ts +88 -0
  95. package/src/slice-remove-field.ts +117 -0
  96. package/src/slice-remove-variation.ts +108 -0
  97. package/src/slice-remove.ts +81 -0
  98. package/src/slice-rename.ts +112 -0
  99. package/src/slice-view.ts +77 -0
  100. package/src/slice.ts +90 -0
  101. package/src/sync.ts +309 -0
  102. package/src/token-create.ts +185 -0
  103. package/src/token-delete.ts +161 -0
  104. package/src/token-list.ts +212 -0
  105. package/src/token-set-name.ts +165 -0
  106. package/src/token.ts +60 -0
  107. package/src/webhook-add-header.ts +118 -0
  108. package/src/webhook-create.ts +152 -0
  109. package/src/webhook-disable.ts +109 -0
  110. package/src/webhook-enable.ts +132 -0
  111. package/src/webhook-list.ts +93 -0
  112. package/src/webhook-remove-header.ts +117 -0
  113. package/src/webhook-remove.ts +106 -0
  114. package/src/webhook-set-triggers.ts +148 -0
  115. package/src/webhook-status.ts +90 -0
  116. package/src/webhook-test.ts +106 -0
  117. package/src/webhook-view.ts +147 -0
  118. package/src/webhook.ts +95 -0
  119. package/src/whoami.ts +62 -0
@@ -0,0 +1,158 @@
1
+ import type { CustomType, UID } 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 { findUpward } from "./lib/file";
8
+ import { stringify } from "./lib/json";
9
+
10
+ const HELP = `
11
+ Add a UID (unique identifier) field to an existing custom type.
12
+
13
+ USAGE
14
+ prismic custom-type add-field uid <type-id> <field-id> [flags]
15
+
16
+ ARGUMENTS
17
+ type-id Custom type identifier (required)
18
+ field-id Field identifier (required)
19
+
20
+ FLAGS
21
+ -t, --tab string Target tab (default: first existing tab, or "Main")
22
+ -l, --label string Display label for the field
23
+ -p, --placeholder string Placeholder text
24
+ -h, --help Show help for command
25
+
26
+ EXAMPLES
27
+ prismic custom-type add-field uid page uid
28
+ prismic custom-type add-field uid article slug --label "URL Slug"
29
+ prismic custom-type add-field uid product sku --placeholder "Enter unique SKU"
30
+ `.trim();
31
+
32
+ const CustomTypeSchema = v.object({
33
+ id: v.string(),
34
+ label: v.string(),
35
+ repeatable: v.boolean(),
36
+ status: v.boolean(),
37
+ format: v.string(),
38
+ json: v.record(v.string(), v.record(v.string(), v.unknown())),
39
+ });
40
+
41
+ export async function customTypeAddFieldUid(): Promise<void> {
42
+ const {
43
+ values: { help, tab, label, placeholder },
44
+ positionals: [typeId, fieldId],
45
+ } = parseArgs({
46
+ args: process.argv.slice(5), // skip: node, script, "custom-type", "add-field", "uid"
47
+ options: {
48
+ tab: { type: "string", short: "t" },
49
+ label: { type: "string", short: "l" },
50
+ placeholder: { type: "string", short: "p" },
51
+ help: { type: "boolean", short: "h" },
52
+ },
53
+ allowPositionals: true,
54
+ });
55
+
56
+ if (help) {
57
+ console.info(HELP);
58
+ return;
59
+ }
60
+
61
+ if (!typeId) {
62
+ console.error("Missing required argument: type-id\n");
63
+ console.error("Usage: prismic custom-type add-field uid <type-id> <field-id>");
64
+ process.exitCode = 1;
65
+ return;
66
+ }
67
+
68
+ if (!fieldId) {
69
+ console.error("Missing required argument: field-id\n");
70
+ console.error("Usage: prismic custom-type add-field uid <type-id> <field-id>");
71
+ process.exitCode = 1;
72
+ return;
73
+ }
74
+
75
+ // Find the custom type file
76
+ const projectRoot = await findUpward("package.json");
77
+ if (!projectRoot) {
78
+ console.error("Could not find project root (no package.json found)");
79
+ process.exitCode = 1;
80
+ return;
81
+ }
82
+
83
+ const modelPath = new URL(`customtypes/${typeId}/index.json`, projectRoot);
84
+
85
+ // Read and parse the model
86
+ let model: CustomType;
87
+ try {
88
+ const contents = await readFile(modelPath, "utf8");
89
+ const result = v.safeParse(CustomTypeSchema, JSON.parse(contents));
90
+ if (!result.success) {
91
+ console.error(`Invalid custom type model: ${modelPath.href}`);
92
+ process.exitCode = 1;
93
+ return;
94
+ }
95
+ model = result.output as CustomType;
96
+ } catch (error) {
97
+ if (error instanceof Error && "code" in error && error.code === "ENOENT") {
98
+ console.error(`Custom type not found: ${typeId}\n`);
99
+ console.error(`Create it first with: prismic custom-type create ${typeId}`);
100
+ process.exitCode = 1;
101
+ return;
102
+ }
103
+ if (error instanceof Error) {
104
+ console.error(`Failed to read custom type: ${error.message}`);
105
+ } else {
106
+ console.error("Failed to read custom type");
107
+ }
108
+ process.exitCode = 1;
109
+ return;
110
+ }
111
+
112
+ // Determine target tab
113
+ const existingTabs = Object.keys(model.json);
114
+ const targetTab = tab ?? existingTabs[0] ?? "Main";
115
+
116
+ // Initialize tab if it doesn't exist
117
+ if (!model.json[targetTab]) {
118
+ model.json[targetTab] = {};
119
+ }
120
+
121
+ // Check if field already exists in any tab
122
+ for (const [tabName, tabFields] of Object.entries(model.json)) {
123
+ if (tabFields[fieldId]) {
124
+ console.error(`Field "${fieldId}" already exists in tab "${tabName}"`);
125
+ process.exitCode = 1;
126
+ return;
127
+ }
128
+ }
129
+
130
+ // Build field definition
131
+ const fieldDefinition: UID = {
132
+ type: "UID",
133
+ config: {
134
+ ...(label && { label }),
135
+ ...(placeholder && { placeholder }),
136
+ },
137
+ };
138
+
139
+ // Add field to model
140
+ model.json[targetTab][fieldId] = fieldDefinition;
141
+
142
+ // Write updated model
143
+ try {
144
+ await writeFile(modelPath, stringify(model));
145
+ } catch (error) {
146
+ if (error instanceof Error) {
147
+ console.error(`Failed to update custom type: ${error.message}`);
148
+ } else {
149
+ console.error("Failed to update custom type");
150
+ }
151
+ process.exitCode = 1;
152
+ return;
153
+ }
154
+
155
+ console.info(
156
+ `Added field "${fieldId}" (UID) to "${targetTab}" tab in ${typeId}`,
157
+ );
158
+ }
@@ -0,0 +1,111 @@
1
+ import { parseArgs } from "node:util";
2
+
3
+ import { customTypeAddFieldBoolean } from "./custom-type-add-field-boolean";
4
+ import { customTypeAddFieldColor } from "./custom-type-add-field-color";
5
+ import { customTypeAddFieldDate } from "./custom-type-add-field-date";
6
+ import { customTypeAddFieldEmbed } from "./custom-type-add-field-embed";
7
+ import { customTypeAddFieldGeoPoint } from "./custom-type-add-field-geo-point";
8
+ import { customTypeAddFieldImage } from "./custom-type-add-field-image";
9
+ import { customTypeAddFieldKeyText } from "./custom-type-add-field-key-text";
10
+ import { customTypeAddFieldLink } from "./custom-type-add-field-link";
11
+ import { customTypeAddFieldNumber } from "./custom-type-add-field-number";
12
+ import { customTypeAddFieldRichText } from "./custom-type-add-field-rich-text";
13
+ import { customTypeAddFieldSelect } from "./custom-type-add-field-select";
14
+ import { customTypeAddFieldTimestamp } from "./custom-type-add-field-timestamp";
15
+ import { customTypeAddFieldUid } from "./custom-type-add-field-uid";
16
+
17
+ const HELP = `
18
+ Add a field to an existing custom type.
19
+
20
+ USAGE
21
+ prismic custom-type add-field <field-type> <type-id> <field-id> [flags]
22
+
23
+ FIELD TYPES
24
+ boolean Boolean toggle
25
+ color Color picker
26
+ date Date picker
27
+ embed Embed (oEmbed)
28
+ geo-point Geographic coordinates
29
+ image Image
30
+ key-text Single-line text
31
+ link Any link type
32
+ number Number
33
+ rich-text Rich text editor
34
+ select Dropdown select
35
+ timestamp Date and time
36
+ uid Unique identifier
37
+
38
+ FLAGS
39
+ -h, --help Show help for command
40
+
41
+ LEARN MORE
42
+ Use \`prismic custom-type add-field <field-type> --help\` for more information.
43
+
44
+ EXAMPLES
45
+ prismic custom-type add-field key-text homepage meta_title --tab "SEO"
46
+ prismic custom-type add-field link homepage button --allow-text
47
+ prismic custom-type add-field rich-text homepage body --multi "paragraph,heading2,strong,em"
48
+ prismic custom-type add-field select homepage layout --option "full" --option "sidebar"
49
+ `.trim();
50
+
51
+ export async function customTypeAddField(): Promise<void> {
52
+ const {
53
+ positionals: [fieldType],
54
+ } = parseArgs({
55
+ args: process.argv.slice(4), // skip: node, script, "custom-type", "add-field"
56
+ options: {
57
+ help: { type: "boolean", short: "h" },
58
+ },
59
+ allowPositionals: true,
60
+ strict: false,
61
+ });
62
+
63
+ switch (fieldType) {
64
+ case "boolean":
65
+ await customTypeAddFieldBoolean();
66
+ break;
67
+ case "color":
68
+ await customTypeAddFieldColor();
69
+ break;
70
+ case "date":
71
+ await customTypeAddFieldDate();
72
+ break;
73
+ case "embed":
74
+ await customTypeAddFieldEmbed();
75
+ break;
76
+ case "geo-point":
77
+ await customTypeAddFieldGeoPoint();
78
+ break;
79
+ case "image":
80
+ await customTypeAddFieldImage();
81
+ break;
82
+ case "key-text":
83
+ await customTypeAddFieldKeyText();
84
+ break;
85
+ case "link":
86
+ await customTypeAddFieldLink();
87
+ break;
88
+ case "number":
89
+ await customTypeAddFieldNumber();
90
+ break;
91
+ case "rich-text":
92
+ await customTypeAddFieldRichText();
93
+ break;
94
+ case "select":
95
+ await customTypeAddFieldSelect();
96
+ break;
97
+ case "timestamp":
98
+ await customTypeAddFieldTimestamp();
99
+ break;
100
+ case "uid":
101
+ await customTypeAddFieldUid();
102
+ break;
103
+ default: {
104
+ if (fieldType) {
105
+ console.error(`Unknown field type: ${fieldType}\n`);
106
+ process.exitCode = 1;
107
+ }
108
+ console.info(HELP);
109
+ }
110
+ }
111
+ }
@@ -0,0 +1,221 @@
1
+ import type {
2
+ CustomType,
3
+ DynamicSlices,
4
+ SharedSliceRef,
5
+ } from "@prismicio/types-internal/lib/customtypes";
6
+
7
+ import { readFile, writeFile } from "node:fs/promises";
8
+ import { parseArgs } from "node:util";
9
+ import * as v from "valibot";
10
+
11
+ import { findUpward } from "./lib/file";
12
+ import { stringify } from "./lib/json";
13
+ import { findSliceModel } from "./lib/slice";
14
+
15
+ const HELP = `
16
+ Connect a shared slice to a custom type's slice zone.
17
+
18
+ USAGE
19
+ prismic custom-type connect-slice <type-id> <slice-id> [flags]
20
+
21
+ ARGUMENTS
22
+ type-id Custom type identifier (required)
23
+ slice-id Slice identifier (required)
24
+
25
+ FLAGS
26
+ -z, --slice-zone string Target slice zone field ID (default: "slices")
27
+ -h, --help Show help for command
28
+
29
+ EXAMPLES
30
+ prismic custom-type connect-slice homepage CallToAction
31
+ prismic custom-type connect-slice homepage CallToAction --slice-zone slices
32
+ prismic custom-type connect-slice article HeroSection -z body
33
+ `.trim();
34
+
35
+ const CustomTypeSchema = v.object({
36
+ id: v.string(),
37
+ label: v.string(),
38
+ repeatable: v.boolean(),
39
+ status: v.boolean(),
40
+ format: v.string(),
41
+ json: v.record(v.string(), v.record(v.string(), v.unknown())),
42
+ });
43
+
44
+ export async function customTypeConnectSlice(): Promise<void> {
45
+ const {
46
+ values: { help, "slice-zone": sliceZoneId },
47
+ positionals: [typeId, sliceId],
48
+ } = parseArgs({
49
+ args: process.argv.slice(4), // skip: node, script, "custom-type", "connect-slice"
50
+ options: {
51
+ "slice-zone": { type: "string", short: "z" },
52
+ help: { type: "boolean", short: "h" },
53
+ },
54
+ allowPositionals: true,
55
+ });
56
+
57
+ if (help) {
58
+ console.info(HELP);
59
+ return;
60
+ }
61
+
62
+ if (!typeId) {
63
+ console.error("Missing required argument: type-id\n");
64
+ console.error(
65
+ "Usage: prismic custom-type connect-slice <type-id> <slice-id>",
66
+ );
67
+ process.exitCode = 1;
68
+ return;
69
+ }
70
+
71
+ if (!sliceId) {
72
+ console.error("Missing required argument: slice-id\n");
73
+ console.error(
74
+ "Usage: prismic custom-type connect-slice <type-id> <slice-id>",
75
+ );
76
+ process.exitCode = 1;
77
+ return;
78
+ }
79
+
80
+ // Verify the slice exists
81
+ const sliceResult = await findSliceModel(sliceId);
82
+ if (!sliceResult.ok) {
83
+ console.error(sliceResult.error);
84
+ process.exitCode = 1;
85
+ return;
86
+ }
87
+
88
+ // Find the custom type file
89
+ const projectRoot = await findUpward("package.json");
90
+ if (!projectRoot) {
91
+ console.error("Could not find project root (no package.json found)");
92
+ process.exitCode = 1;
93
+ return;
94
+ }
95
+
96
+ const modelPath = new URL(`customtypes/${typeId}/index.json`, projectRoot);
97
+
98
+ // Read and parse the model
99
+ let model: CustomType;
100
+ try {
101
+ const contents = await readFile(modelPath, "utf8");
102
+ const result = v.safeParse(CustomTypeSchema, JSON.parse(contents));
103
+ if (!result.success) {
104
+ console.error(`Invalid custom type model: ${modelPath.href}`);
105
+ process.exitCode = 1;
106
+ return;
107
+ }
108
+ model = result.output as CustomType;
109
+ } catch (error) {
110
+ if (
111
+ error instanceof Error &&
112
+ "code" in error &&
113
+ error.code === "ENOENT"
114
+ ) {
115
+ console.error(`Custom type not found: ${typeId}\n`);
116
+ console.error(
117
+ `Create it first with: prismic custom-type create ${typeId}`,
118
+ );
119
+ process.exitCode = 1;
120
+ return;
121
+ }
122
+ if (error instanceof Error) {
123
+ console.error(`Failed to read custom type: ${error.message}`);
124
+ } else {
125
+ console.error("Failed to read custom type");
126
+ }
127
+ process.exitCode = 1;
128
+ return;
129
+ }
130
+
131
+ const targetSliceZoneId = sliceZoneId ?? "slices";
132
+
133
+ // Find existing slice zone or create a new one
134
+ let sliceZone: DynamicSlices | undefined;
135
+ let sliceZoneFieldId: string | undefined;
136
+
137
+ // Search all tabs for a Slices field matching the target ID
138
+ for (const [, tabFields] of Object.entries(model.json)) {
139
+ for (const [fieldId, field] of Object.entries(tabFields)) {
140
+ if (
141
+ (field as { type?: string }).type === "Slices" &&
142
+ fieldId === targetSliceZoneId
143
+ ) {
144
+ sliceZone = field as DynamicSlices;
145
+ sliceZoneFieldId = fieldId;
146
+ break;
147
+ }
148
+ }
149
+ if (sliceZone) break;
150
+ }
151
+
152
+ // Handle slice zone not found
153
+ if (!sliceZone) {
154
+ if (sliceZoneId) {
155
+ // User specified a slice zone that doesn't exist
156
+ console.error(
157
+ `Slice zone "${sliceZoneId}" not found in custom type "${typeId}"`,
158
+ );
159
+ process.exitCode = 1;
160
+ return;
161
+ }
162
+
163
+ // Create a new slice zone in the first tab
164
+ const existingTabs = Object.keys(model.json);
165
+ const targetTab = existingTabs[0] ?? "Main";
166
+
167
+ // Initialize tab if it doesn't exist
168
+ if (!model.json[targetTab]) {
169
+ model.json[targetTab] = {};
170
+ }
171
+
172
+ const newSliceZone: DynamicSlices = {
173
+ type: "Slices",
174
+ fieldset: "Slice Zone",
175
+ config: {
176
+ choices: {},
177
+ },
178
+ };
179
+
180
+ model.json[targetTab][targetSliceZoneId] = newSliceZone;
181
+ sliceZone = newSliceZone;
182
+ sliceZoneFieldId = targetSliceZoneId;
183
+ }
184
+
185
+ // Ensure config and choices exist
186
+ if (!sliceZone.config) {
187
+ sliceZone.config = { choices: {} };
188
+ }
189
+ if (!sliceZone.config.choices) {
190
+ sliceZone.config.choices = {};
191
+ }
192
+
193
+ // Check if slice is already connected
194
+ if (sliceId in sliceZone.config.choices) {
195
+ console.info(
196
+ `Slice "${sliceId}" is already connected to slice zone "${sliceZoneFieldId}" in ${typeId}`,
197
+ );
198
+ return;
199
+ }
200
+
201
+ // Add the slice reference
202
+ const sliceRef: SharedSliceRef = { type: "SharedSlice" };
203
+ sliceZone.config.choices[sliceId] = sliceRef;
204
+
205
+ // Write updated model
206
+ try {
207
+ await writeFile(modelPath, stringify(model));
208
+ } catch (error) {
209
+ if (error instanceof Error) {
210
+ console.error(`Failed to update custom type: ${error.message}`);
211
+ } else {
212
+ console.error("Failed to update custom type");
213
+ }
214
+ process.exitCode = 1;
215
+ return;
216
+ }
217
+
218
+ console.info(
219
+ `Connected slice "${sliceId}" to slice zone "${sliceZoneFieldId}" in ${typeId}`,
220
+ );
221
+ }
@@ -0,0 +1,92 @@
1
+ import type { CustomType } from "@prismicio/types-internal/lib/customtypes";
2
+
3
+ import { mkdir, writeFile } from "node:fs/promises";
4
+ import { parseArgs } from "node:util";
5
+
6
+ import { findUpward } from "./lib/file";
7
+ import { stringify } from "./lib/json";
8
+
9
+ const HELP = `
10
+ Create a new custom type in a Prismic repository.
11
+
12
+ USAGE
13
+ prismic custom-type create <id> [flags]
14
+
15
+ ARGUMENTS
16
+ id Custom type identifier (required)
17
+
18
+ FLAGS
19
+ -n, --name string Display name for the custom type
20
+ --single Create as a singleton (non-repeatable) type
21
+ -h, --help Show help for command
22
+
23
+ LEARN MORE
24
+ Use \`prismic custom-type <command> --help\` for more information about a command.
25
+ `.trim();
26
+
27
+ export async function customTypeCreate(): Promise<void> {
28
+ const {
29
+ values: { help, name, single },
30
+ positionals: [id],
31
+ } = parseArgs({
32
+ args: process.argv.slice(4), // skip: node, script, "custom-type", "create"
33
+ options: {
34
+ name: { type: "string", short: "n" },
35
+ single: { type: "boolean" },
36
+ help: { type: "boolean", short: "h" },
37
+ },
38
+ allowPositionals: true,
39
+ });
40
+
41
+ if (help) {
42
+ console.info(HELP);
43
+ return;
44
+ }
45
+
46
+ if (!id) {
47
+ console.error("Missing required argument: id");
48
+ process.exitCode = 1;
49
+ return;
50
+ }
51
+
52
+ const model = {
53
+ id,
54
+ label: name ?? pascalCase(id),
55
+ repeatable: !single,
56
+ status: true,
57
+ format: "custom",
58
+ json: {
59
+ Main: {},
60
+ },
61
+ } satisfies CustomType;
62
+
63
+ const projectRoot = await findUpward("package.json");
64
+ if (!projectRoot) {
65
+ console.error("Could not find project root (no package.json found)");
66
+ process.exitCode = 1;
67
+ return;
68
+ }
69
+
70
+ const customTypesDirectory = new URL("customtypes/", projectRoot);
71
+ const typeDirectory = new URL(id + "/", customTypesDirectory);
72
+ const modelPath = new URL("index.json", typeDirectory);
73
+
74
+ try {
75
+ await mkdir(new URL(".", modelPath), { recursive: true });
76
+ await writeFile(modelPath, stringify(model));
77
+ } catch (error) {
78
+ if (error instanceof Error) {
79
+ console.error(`Failed to create custom type: ${error.message}`);
80
+ } else {
81
+ console.error(`Failed to create custom type`);
82
+ }
83
+ process.exitCode = 1;
84
+ return;
85
+ }
86
+
87
+ console.info(`Created custom type at ${modelPath.href}`);
88
+ }
89
+
90
+ export function pascalCase(input: string): string {
91
+ return input.toLowerCase().replace(/(^|[-_\s]+)(.)?/g, (_, __, c) => c?.toUpperCase() ?? "");
92
+ }