@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.
- package/LICENSE +202 -0
- package/README.md +98 -0
- package/dist/index.mjs +2548 -0
- package/package.json +53 -0
- package/src/codegen-types.ts +82 -0
- package/src/codegen.ts +45 -0
- package/src/custom-type-add-field-boolean.ts +192 -0
- package/src/custom-type-add-field-color.ts +177 -0
- package/src/custom-type-add-field-date.ts +180 -0
- package/src/custom-type-add-field-embed.ts +177 -0
- package/src/custom-type-add-field-geo-point.ts +174 -0
- package/src/custom-type-add-field-image.ts +177 -0
- package/src/custom-type-add-field-key-text.ts +177 -0
- package/src/custom-type-add-field-link.ts +201 -0
- package/src/custom-type-add-field-number.ts +209 -0
- package/src/custom-type-add-field-rich-text.ts +202 -0
- package/src/custom-type-add-field-select.ts +192 -0
- package/src/custom-type-add-field-timestamp.ts +180 -0
- package/src/custom-type-add-field-uid.ts +177 -0
- package/src/custom-type-add-field.ts +111 -0
- package/src/custom-type-connect-slice.ts +220 -0
- package/src/custom-type-create.ts +118 -0
- package/src/custom-type-disconnect-slice.ts +177 -0
- package/src/custom-type-list.ts +110 -0
- package/src/custom-type-remove-field.ts +177 -0
- package/src/custom-type-remove.ts +144 -0
- package/src/custom-type-set-name.ts +144 -0
- package/src/custom-type-view.ts +118 -0
- package/src/custom-type.ts +85 -0
- package/src/index.ts +127 -0
- package/src/init.ts +64 -0
- package/src/lib/auth.ts +83 -0
- package/src/lib/config.ts +111 -0
- package/src/lib/custom-types-api.ts +438 -0
- package/src/lib/file.ts +49 -0
- package/src/lib/framework.ts +143 -0
- package/src/lib/json.ts +3 -0
- package/src/lib/request.ts +116 -0
- package/src/lib/slice.ts +115 -0
- package/src/lib/string.ts +6 -0
- package/src/lib/url.ts +25 -0
- package/src/locale-add.ts +116 -0
- package/src/locale-list.ts +107 -0
- package/src/locale-remove.ts +88 -0
- package/src/locale-set-default.ts +131 -0
- package/src/locale.ts +60 -0
- package/src/login.ts +152 -0
- package/src/logout.ts +36 -0
- package/src/page-type-add-field-boolean.ts +192 -0
- package/src/page-type-add-field-color.ts +177 -0
- package/src/page-type-add-field-date.ts +180 -0
- package/src/page-type-add-field-embed.ts +177 -0
- package/src/page-type-add-field-geo-point.ts +174 -0
- package/src/page-type-add-field-image.ts +177 -0
- package/src/page-type-add-field-key-text.ts +177 -0
- package/src/page-type-add-field-link.ts +201 -0
- package/src/page-type-add-field-number.ts +209 -0
- package/src/page-type-add-field-rich-text.ts +202 -0
- package/src/page-type-add-field-select.ts +192 -0
- package/src/page-type-add-field-timestamp.ts +180 -0
- package/src/page-type-add-field-uid.ts +177 -0
- package/src/page-type-add-field.ts +111 -0
- package/src/page-type-connect-slice.ts +220 -0
- package/src/page-type-create.ts +142 -0
- package/src/page-type-disconnect-slice.ts +177 -0
- package/src/page-type-list.ts +109 -0
- package/src/page-type-remove-field.ts +177 -0
- package/src/page-type-remove.ts +144 -0
- package/src/page-type-set-name.ts +144 -0
- package/src/page-type-set-repeatable.ts +153 -0
- package/src/page-type-view.ts +118 -0
- package/src/page-type.ts +90 -0
- package/src/preview-add.ts +126 -0
- package/src/preview-get-simulator.ts +104 -0
- package/src/preview-list.ts +106 -0
- package/src/preview-remove-simulator.ts +80 -0
- package/src/preview-remove.ts +109 -0
- package/src/preview-set-name.ts +137 -0
- package/src/preview-set-simulator.ts +116 -0
- package/src/preview.ts +75 -0
- package/src/pull.ts +247 -0
- package/src/push.ts +405 -0
- package/src/repo-create.ts +136 -0
- package/src/repo-get-access.ts +86 -0
- package/src/repo-list.ts +100 -0
- package/src/repo-set-access.ts +100 -0
- package/src/repo-set-name.ts +102 -0
- package/src/repo-view.ts +113 -0
- package/src/repo.ts +70 -0
- package/src/slice-add-field-boolean.ts +173 -0
- package/src/slice-add-field-color.ts +158 -0
- package/src/slice-add-field-date.ts +158 -0
- package/src/slice-add-field-embed.ts +158 -0
- package/src/slice-add-field-geo-point.ts +155 -0
- package/src/slice-add-field-image.ts +155 -0
- package/src/slice-add-field-key-text.ts +158 -0
- package/src/slice-add-field-link.ts +178 -0
- package/src/slice-add-field-number.ts +158 -0
- package/src/slice-add-field-rich-text.ts +183 -0
- package/src/slice-add-field-select.ts +173 -0
- package/src/slice-add-field-timestamp.ts +158 -0
- package/src/slice-add-field.ts +106 -0
- package/src/slice-add-variation.ts +145 -0
- package/src/slice-create.ts +148 -0
- package/src/slice-list-variations.ts +67 -0
- package/src/slice-list.ts +88 -0
- package/src/slice-remove-field.ts +128 -0
- package/src/slice-remove-variation.ts +118 -0
- package/src/slice-remove.ts +97 -0
- package/src/slice-rename.ts +128 -0
- package/src/slice-view.ts +77 -0
- package/src/slice.ts +90 -0
- package/src/status.ts +733 -0
- package/src/token-create.ts +203 -0
- package/src/token-delete.ts +182 -0
- package/src/token-list.ts +223 -0
- package/src/token-set-name.ts +193 -0
- package/src/token.ts +60 -0
- package/src/webhook-add-header.ts +118 -0
- package/src/webhook-create.ts +152 -0
- package/src/webhook-disable.ts +109 -0
- package/src/webhook-enable.ts +132 -0
- package/src/webhook-list.ts +93 -0
- package/src/webhook-remove-header.ts +117 -0
- package/src/webhook-remove.ts +106 -0
- package/src/webhook-set-triggers.ts +148 -0
- package/src/webhook-status.ts +90 -0
- package/src/webhook-test.ts +106 -0
- package/src/webhook-view.ts +147 -0
- package/src/webhook.ts +95 -0
- package/src/whoami.ts +62 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import type { CustomType, DynamicSlices } 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
|
+
Disconnect a shared slice from a custom type's slice zone.
|
|
13
|
+
|
|
14
|
+
USAGE
|
|
15
|
+
prismic custom-type disconnect-slice <type-id> <slice-id> [flags]
|
|
16
|
+
|
|
17
|
+
ARGUMENTS
|
|
18
|
+
type-id Custom type identifier (required)
|
|
19
|
+
slice-id Slice identifier (required)
|
|
20
|
+
|
|
21
|
+
Types are generated by default after changes. Use --no-types to skip.
|
|
22
|
+
|
|
23
|
+
FLAGS
|
|
24
|
+
-z, --slice-zone string Target slice zone field ID (default: "slices")
|
|
25
|
+
--types string Output file for generated types (default: "prismicio-types.d.ts")
|
|
26
|
+
--no-types Skip type generation
|
|
27
|
+
-h, --help Show help for command
|
|
28
|
+
|
|
29
|
+
EXAMPLES
|
|
30
|
+
prismic custom-type disconnect-slice homepage CallToAction
|
|
31
|
+
prismic custom-type disconnect-slice homepage CallToAction --slice-zone slices
|
|
32
|
+
prismic custom-type disconnect-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 customTypeDisconnectSlice(): Promise<void> {
|
|
45
|
+
const {
|
|
46
|
+
values: { help, "slice-zone": sliceZoneId, types, "no-types": noTypes },
|
|
47
|
+
positionals: [typeId, sliceId],
|
|
48
|
+
} = parseArgs({
|
|
49
|
+
args: process.argv.slice(4), // skip: node, script, "custom-type", "disconnect-slice"
|
|
50
|
+
options: {
|
|
51
|
+
"slice-zone": { type: "string", short: "z" },
|
|
52
|
+
types: { type: "string" },
|
|
53
|
+
"no-types": { type: "boolean" },
|
|
54
|
+
help: { type: "boolean", short: "h" },
|
|
55
|
+
},
|
|
56
|
+
allowPositionals: true,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
if (help) {
|
|
60
|
+
console.info(HELP);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (!typeId) {
|
|
65
|
+
console.error("Missing required argument: type-id\n");
|
|
66
|
+
console.error("Usage: prismic custom-type disconnect-slice <type-id> <slice-id>");
|
|
67
|
+
process.exitCode = 1;
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (!sliceId) {
|
|
72
|
+
console.error("Missing required argument: slice-id\n");
|
|
73
|
+
console.error("Usage: prismic custom-type disconnect-slice <type-id> <slice-id>");
|
|
74
|
+
process.exitCode = 1;
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Find the custom type file
|
|
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 custom 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(`Custom type not found: ${typeId}\n`);
|
|
102
|
+
console.error(`Create it first with: prismic custom-type create ${typeId}`);
|
|
103
|
+
process.exitCode = 1;
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
if (error instanceof Error) {
|
|
107
|
+
console.error(`Failed to read custom type: ${error.message}`);
|
|
108
|
+
} else {
|
|
109
|
+
console.error("Failed to read custom type");
|
|
110
|
+
}
|
|
111
|
+
process.exitCode = 1;
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const targetSliceZoneId = sliceZoneId ?? "slices";
|
|
116
|
+
|
|
117
|
+
// Find existing slice zone
|
|
118
|
+
let sliceZone: DynamicSlices | undefined;
|
|
119
|
+
let sliceZoneFieldId: string | undefined;
|
|
120
|
+
|
|
121
|
+
// Search all tabs for a Slices field matching the target ID
|
|
122
|
+
for (const [, tabFields] of Object.entries(model.json)) {
|
|
123
|
+
for (const [fieldId, field] of Object.entries(tabFields)) {
|
|
124
|
+
if ((field as { type?: string }).type === "Slices" && fieldId === targetSliceZoneId) {
|
|
125
|
+
sliceZone = field as DynamicSlices;
|
|
126
|
+
sliceZoneFieldId = fieldId;
|
|
127
|
+
break;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (sliceZone) break;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Slice zone must exist for disconnect
|
|
134
|
+
if (!sliceZone) {
|
|
135
|
+
console.error(`Slice zone "${targetSliceZoneId}" not found in custom type "${typeId}"`);
|
|
136
|
+
process.exitCode = 1;
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Check if slice is connected
|
|
141
|
+
if (!sliceZone.config?.choices || !(sliceId in sliceZone.config.choices)) {
|
|
142
|
+
console.error(
|
|
143
|
+
`Slice "${sliceId}" is not connected to slice zone "${sliceZoneFieldId}" in ${typeId}`,
|
|
144
|
+
);
|
|
145
|
+
process.exitCode = 1;
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Remove the slice reference
|
|
150
|
+
delete sliceZone.config.choices[sliceId];
|
|
151
|
+
|
|
152
|
+
// Write updated model
|
|
153
|
+
try {
|
|
154
|
+
await writeFile(modelPath, stringify(model));
|
|
155
|
+
} catch (error) {
|
|
156
|
+
if (error instanceof Error) {
|
|
157
|
+
console.error(`Failed to update custom type: ${error.message}`);
|
|
158
|
+
} else {
|
|
159
|
+
console.error("Failed to update custom type");
|
|
160
|
+
}
|
|
161
|
+
process.exitCode = 1;
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
console.info(
|
|
166
|
+
`Disconnected slice "${sliceId}" from slice zone "${sliceZoneFieldId}" in ${typeId}`,
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
if (!noTypes) {
|
|
170
|
+
try {
|
|
171
|
+
await buildTypes({ output: types });
|
|
172
|
+
console.info(`Updated types in ${types ?? "prismicio-types.d.ts"}`);
|
|
173
|
+
} catch (error) {
|
|
174
|
+
console.warn(`Could not generate types: ${error instanceof Error ? error.message : error}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
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 custom types in a Prismic project.
|
|
9
|
+
|
|
10
|
+
USAGE
|
|
11
|
+
prismic custom-type list [flags]
|
|
12
|
+
|
|
13
|
+
FLAGS
|
|
14
|
+
--json Output as JSON
|
|
15
|
+
-h, --help Show help for command
|
|
16
|
+
|
|
17
|
+
EXAMPLES
|
|
18
|
+
prismic custom-type list
|
|
19
|
+
prismic custom-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 customTypeList(): Promise<void> {
|
|
32
|
+
const {
|
|
33
|
+
values: { help, json },
|
|
34
|
+
} = parseArgs({
|
|
35
|
+
args: process.argv.slice(4), // skip: node, script, "custom-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 custom types found.");
|
|
67
|
+
}
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const customTypes: { 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
|
+
// Custom types have format !== "page" (either "custom" or undefined)
|
|
80
|
+
if (result.success && result.output.format !== "page") {
|
|
81
|
+
customTypes.push({
|
|
82
|
+
id: result.output.id,
|
|
83
|
+
label: result.output.label,
|
|
84
|
+
repeatable: result.output.repeatable,
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
} catch {
|
|
88
|
+
// Skip directories without valid index.json
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (customTypes.length === 0) {
|
|
93
|
+
if (json) {
|
|
94
|
+
console.info(JSON.stringify([]));
|
|
95
|
+
} else {
|
|
96
|
+
console.info("No custom types found.");
|
|
97
|
+
}
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (json) {
|
|
102
|
+
console.info(JSON.stringify(customTypes, null, 2));
|
|
103
|
+
} else {
|
|
104
|
+
console.info("ID\tLABEL\tTYPE");
|
|
105
|
+
for (const customType of customTypes) {
|
|
106
|
+
const typeLabel = customType.repeatable ? "repeatable" : "singleton";
|
|
107
|
+
console.info(`${customType.id}\t${customType.label}\t${typeLabel}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
@@ -0,0 +1,177 @@
|
|
|
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 custom type.
|
|
13
|
+
|
|
14
|
+
USAGE
|
|
15
|
+
prismic custom-type remove-field <type-id> <field-id> [flags]
|
|
16
|
+
|
|
17
|
+
ARGUMENTS
|
|
18
|
+
type-id Custom type identifier (required)
|
|
19
|
+
field-id Field identifier (required)
|
|
20
|
+
|
|
21
|
+
Types are generated by default after changes. Use --no-types to skip.
|
|
22
|
+
|
|
23
|
+
FLAGS
|
|
24
|
+
--tab string Specific tab (searches all tabs if not specified)
|
|
25
|
+
--types string Output file for generated types (default: "prismicio-types.d.ts")
|
|
26
|
+
--no-types Skip type generation
|
|
27
|
+
-h, --help Show help for command
|
|
28
|
+
|
|
29
|
+
EXAMPLES
|
|
30
|
+
prismic custom-type remove-field settings title
|
|
31
|
+
prismic custom-type remove-field settings description --tab "Content"
|
|
32
|
+
`.trim();
|
|
33
|
+
|
|
34
|
+
const CustomTypeSchema = v.object({
|
|
35
|
+
id: v.string(),
|
|
36
|
+
label: v.string(),
|
|
37
|
+
repeatable: v.boolean(),
|
|
38
|
+
status: v.boolean(),
|
|
39
|
+
format: v.optional(v.string()),
|
|
40
|
+
json: v.record(v.string(), v.record(v.string(), v.unknown())),
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
export async function customTypeRemoveField(): Promise<void> {
|
|
44
|
+
const {
|
|
45
|
+
values: { help, tab, types, "no-types": noTypes },
|
|
46
|
+
positionals: [typeId, fieldId],
|
|
47
|
+
} = parseArgs({
|
|
48
|
+
args: process.argv.slice(4), // skip: node, script, "custom-type", "remove-field"
|
|
49
|
+
options: {
|
|
50
|
+
tab: { type: "string" },
|
|
51
|
+
types: { type: "string" },
|
|
52
|
+
"no-types": { type: "boolean" },
|
|
53
|
+
help: { type: "boolean", short: "h" },
|
|
54
|
+
},
|
|
55
|
+
allowPositionals: true,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
if (help) {
|
|
59
|
+
console.info(HELP);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (!typeId) {
|
|
64
|
+
console.error("Missing required argument: type-id\n");
|
|
65
|
+
console.error("Usage: prismic custom-type remove-field <type-id> <field-id>");
|
|
66
|
+
process.exitCode = 1;
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (!fieldId) {
|
|
71
|
+
console.error("Missing required argument: field-id\n");
|
|
72
|
+
console.error("Usage: prismic custom-type remove-field <type-id> <field-id>");
|
|
73
|
+
process.exitCode = 1;
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const projectRoot = await findUpward("package.json");
|
|
78
|
+
if (!projectRoot) {
|
|
79
|
+
console.error("Could not find project root (no package.json found)");
|
|
80
|
+
process.exitCode = 1;
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const modelPath = new URL(`customtypes/${typeId}/index.json`, projectRoot);
|
|
85
|
+
|
|
86
|
+
// Read and parse the model
|
|
87
|
+
let model: CustomType;
|
|
88
|
+
try {
|
|
89
|
+
const contents = await readFile(modelPath, "utf8");
|
|
90
|
+
const result = v.safeParse(CustomTypeSchema, JSON.parse(contents));
|
|
91
|
+
if (!result.success) {
|
|
92
|
+
console.error(`Invalid custom type model: ${modelPath.href}`);
|
|
93
|
+
process.exitCode = 1;
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
model = result.output as CustomType;
|
|
97
|
+
} catch (error) {
|
|
98
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
99
|
+
console.error(`Custom type not found: ${typeId}\n`);
|
|
100
|
+
console.error(`Create it first with: prismic custom-type create ${typeId}`);
|
|
101
|
+
process.exitCode = 1;
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
if (error instanceof Error) {
|
|
105
|
+
console.error(`Failed to read custom type: ${error.message}`);
|
|
106
|
+
} else {
|
|
107
|
+
console.error("Failed to read custom type");
|
|
108
|
+
}
|
|
109
|
+
process.exitCode = 1;
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Check if this is actually a custom type (not a page type)
|
|
114
|
+
if (model.format === "page") {
|
|
115
|
+
console.error(`"${typeId}" is not a custom type (format: page)`);
|
|
116
|
+
process.exitCode = 1;
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Find and remove the field
|
|
121
|
+
let foundTab: string | undefined;
|
|
122
|
+
|
|
123
|
+
if (tab) {
|
|
124
|
+
// Look in specific tab
|
|
125
|
+
if (!model.json[tab]) {
|
|
126
|
+
console.error(`Tab "${tab}" not found in custom type "${typeId}"`);
|
|
127
|
+
console.error(`Available tabs: ${Object.keys(model.json).join(", ")}`);
|
|
128
|
+
process.exitCode = 1;
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
if (!(fieldId in model.json[tab])) {
|
|
132
|
+
console.error(`Field "${fieldId}" not found in tab "${tab}"`);
|
|
133
|
+
process.exitCode = 1;
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
delete model.json[tab][fieldId];
|
|
137
|
+
foundTab = tab;
|
|
138
|
+
} else {
|
|
139
|
+
// Search all tabs
|
|
140
|
+
for (const [tabName, tabFields] of Object.entries(model.json)) {
|
|
141
|
+
if (fieldId in tabFields) {
|
|
142
|
+
delete tabFields[fieldId];
|
|
143
|
+
foundTab = tabName;
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (!foundTab) {
|
|
148
|
+
console.error(`Field "${fieldId}" not found in any tab of custom type "${typeId}"`);
|
|
149
|
+
process.exitCode = 1;
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Write updated model
|
|
155
|
+
try {
|
|
156
|
+
await writeFile(modelPath, stringify(model));
|
|
157
|
+
} catch (error) {
|
|
158
|
+
if (error instanceof Error) {
|
|
159
|
+
console.error(`Failed to update custom type: ${error.message}`);
|
|
160
|
+
} else {
|
|
161
|
+
console.error("Failed to update custom type");
|
|
162
|
+
}
|
|
163
|
+
process.exitCode = 1;
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
console.info(`Removed field "${fieldId}" from tab "${foundTab}" in custom type "${typeId}"`);
|
|
168
|
+
|
|
169
|
+
if (!noTypes) {
|
|
170
|
+
try {
|
|
171
|
+
await buildTypes({ output: types });
|
|
172
|
+
console.info(`Updated types in ${types ?? "prismicio-types.d.ts"}`);
|
|
173
|
+
} catch (error) {
|
|
174
|
+
console.warn(`Could not generate types: ${error instanceof Error ? error.message : error}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
@@ -0,0 +1,144 @@
|
|
|
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 custom type from the project.
|
|
12
|
+
|
|
13
|
+
USAGE
|
|
14
|
+
prismic custom-type remove <type-id> [flags]
|
|
15
|
+
|
|
16
|
+
ARGUMENTS
|
|
17
|
+
type-id Custom type identifier (required)
|
|
18
|
+
|
|
19
|
+
Types are generated by default after changes. Use --no-types to skip.
|
|
20
|
+
|
|
21
|
+
FLAGS
|
|
22
|
+
-y Confirm removal
|
|
23
|
+
--types string Output file for generated types (default: "prismicio-types.d.ts")
|
|
24
|
+
--no-types Skip type generation
|
|
25
|
+
-h, --help Show help for command
|
|
26
|
+
|
|
27
|
+
EXAMPLES
|
|
28
|
+
prismic custom-type remove settings
|
|
29
|
+
prismic custom-type remove settings -y
|
|
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.optional(v.string()),
|
|
38
|
+
json: v.record(v.string(), v.record(v.string(), v.unknown())),
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
export async function customTypeRemove(): Promise<void> {
|
|
42
|
+
const {
|
|
43
|
+
values: { help, y, types, "no-types": noTypes },
|
|
44
|
+
positionals: [typeId],
|
|
45
|
+
} = parseArgs({
|
|
46
|
+
args: process.argv.slice(4), // skip: node, script, "custom-type", "remove"
|
|
47
|
+
options: {
|
|
48
|
+
y: { type: "boolean", short: "y" },
|
|
49
|
+
types: { type: "string" },
|
|
50
|
+
"no-types": { type: "boolean" },
|
|
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 remove <type-id>");
|
|
64
|
+
process.exitCode = 1;
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const projectRoot = await findUpward("package.json");
|
|
69
|
+
if (!projectRoot) {
|
|
70
|
+
console.error("Could not find project root (no package.json found)");
|
|
71
|
+
process.exitCode = 1;
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const typeDirectory = new URL(`customtypes/${typeId}/`, projectRoot);
|
|
76
|
+
const modelPath = new URL("index.json", typeDirectory);
|
|
77
|
+
|
|
78
|
+
// Verify the custom type exists and is actually a custom type
|
|
79
|
+
let model: CustomType;
|
|
80
|
+
try {
|
|
81
|
+
const contents = await readFile(modelPath, "utf8");
|
|
82
|
+
const result = v.safeParse(CustomTypeSchema, JSON.parse(contents));
|
|
83
|
+
if (!result.success) {
|
|
84
|
+
console.error(`Invalid custom type model: ${modelPath.href}`);
|
|
85
|
+
process.exitCode = 1;
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
model = result.output as CustomType;
|
|
89
|
+
} catch (error) {
|
|
90
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
91
|
+
console.error(`Custom type not found: ${typeId}`);
|
|
92
|
+
process.exitCode = 1;
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (error instanceof Error) {
|
|
96
|
+
console.error(`Failed to read custom type: ${error.message}`);
|
|
97
|
+
} else {
|
|
98
|
+
console.error("Failed to read custom type");
|
|
99
|
+
}
|
|
100
|
+
process.exitCode = 1;
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Check if this is actually a custom type (not a page type)
|
|
105
|
+
if (model.format === "page") {
|
|
106
|
+
console.error(`"${typeId}" is not a custom type (format: page)`);
|
|
107
|
+
process.exitCode = 1;
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Require -y flag to confirm deletion
|
|
112
|
+
if (!y) {
|
|
113
|
+
console.error(
|
|
114
|
+
`Refusing to remove custom type "${typeId}" (this will delete the entire directory).`,
|
|
115
|
+
);
|
|
116
|
+
console.error("Re-run with -y to confirm.");
|
|
117
|
+
process.exitCode = 1;
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Delete the custom type directory
|
|
122
|
+
try {
|
|
123
|
+
await rm(typeDirectory, { recursive: true });
|
|
124
|
+
} catch (error) {
|
|
125
|
+
if (error instanceof Error) {
|
|
126
|
+
console.error(`Failed to remove custom type: ${error.message}`);
|
|
127
|
+
} else {
|
|
128
|
+
console.error("Failed to remove custom type");
|
|
129
|
+
}
|
|
130
|
+
process.exitCode = 1;
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
console.info(`Removed custom type "${typeId}"`);
|
|
135
|
+
|
|
136
|
+
if (!noTypes) {
|
|
137
|
+
try {
|
|
138
|
+
await buildTypes({ output: types });
|
|
139
|
+
console.info(`Updated types in ${types ?? "prismicio-types.d.ts"}`);
|
|
140
|
+
} catch (error) {
|
|
141
|
+
console.warn(`Could not generate types: ${error instanceof Error ? error.message : error}`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|