prismic-ts-codegen 0.0.2
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 +130 -0
- package/bin/cli.mjs +1166 -0
- package/dist/index.cjs +941 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.js +937 -0
- package/dist/index.js.map +1 -0
- package/package.json +87 -0
- package/src/cli/configSchema.ts +64 -0
- package/src/cli/index.ts +125 -0
- package/src/cli/loadConfig.ts +39 -0
- package/src/cli/loadLocaleIDs.ts +34 -0
- package/src/cli/loadModels.ts +88 -0
- package/src/cli/types.ts +30 -0
- package/src/constants.ts +37 -0
- package/src/generateTypes.ts +65 -0
- package/src/index.ts +6 -0
- package/src/lib/addInterfacePropertiesForFields.ts +595 -0
- package/src/lib/addTypeAliasForCustomType.ts +110 -0
- package/src/lib/addTypeAliasForSharedSlice.ts +200 -0
- package/src/lib/buildFieldDocs.ts +71 -0
- package/src/lib/buildSharedSliceInterfaceName.ts +11 -0
- package/src/lib/getAPIIDPath.ts +46 -0
- package/src/lib/getFieldDocumentationURL.ts +13 -0
- package/src/lib/getHumanReadableFieldPath.ts +35 -0
- package/src/lib/getHumanReadableFieldType.ts +50 -0
- package/src/lib/getHumanReadableModelName.ts +40 -0
- package/src/lib/getSourceFileText.ts +14 -0
- package/src/lib/isCustomTypeModel.ts +5 -0
- package/src/lib/isCustomTypeModelField.ts +12 -0
- package/src/lib/isCustomTypeModelSlice.ts +12 -0
- package/src/lib/isSharedSliceModel.ts +7 -0
- package/src/lib/pascalCase.ts +9 -0
- package/src/lib/writeFieldDocsDescription.ts +46 -0
- package/src/types.ts +27 -0
package/bin/cli.mjs
ADDED
|
@@ -0,0 +1,1166 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { readFileSync, existsSync, writeFileSync } from 'fs';
|
|
4
|
+
import { resolve } from 'path';
|
|
5
|
+
import meow from 'meow';
|
|
6
|
+
import { stripIndent } from 'common-tags';
|
|
7
|
+
import { Project } from 'ts-morph';
|
|
8
|
+
import { pascalCase as pascalCase$1, pascalCaseTransformMerge } from 'pascal-case';
|
|
9
|
+
import Joi from 'joi';
|
|
10
|
+
import * as prismic from '@prismicio/client';
|
|
11
|
+
import fetch from 'node-fetch';
|
|
12
|
+
import fg from 'fast-glob';
|
|
13
|
+
import * as prismicCT from '@prismicio/custom-types-client';
|
|
14
|
+
import _jiti from 'jiti';
|
|
15
|
+
|
|
16
|
+
const BLANK_LINE_IDENTIFIER = "// ___BLANK_LINE_TO_BE_REPLACED___";
|
|
17
|
+
const NON_EDITABLE_FILE_HEADER = stripIndent`
|
|
18
|
+
// Code generated by prismic-ts-codegen. DO NOT EDIT.
|
|
19
|
+
${BLANK_LINE_IDENTIFIER}
|
|
20
|
+
`;
|
|
21
|
+
const CUSTOM_TYPES_DOCUMENTATION_URL = "https://prismic.io/docs/core-concepts/custom-types";
|
|
22
|
+
const SHARED_SLICES_DOCUMENTATION_URL = "https://prismic.io/docs/core-concepts/reusing-slices";
|
|
23
|
+
const FIELD_DOCUMENTATION_URLS = {
|
|
24
|
+
UID: "https://prismic.io/docs/core-concepts/uid",
|
|
25
|
+
Boolean: "https://prismic.io/docs/core-concepts/boolean",
|
|
26
|
+
Color: "https://prismic.io/docs/core-concepts/color",
|
|
27
|
+
Date: "https://prismic.io/docs/core-concepts/date",
|
|
28
|
+
Timestamp: "https://prismic.io/docs/core-concepts/timestamp",
|
|
29
|
+
Number: "https://prismic.io/docs/core-concepts/number",
|
|
30
|
+
Text: "https://prismic.io/docs/core-concepts/key-text",
|
|
31
|
+
Select: "https://prismic.io/docs/core-concepts/select",
|
|
32
|
+
StructuredText: "https://prismic.io/docs/core-concepts/rich-text-title",
|
|
33
|
+
Image: "https://prismic.io/docs/core-concepts/image",
|
|
34
|
+
Link: "https://prismic.io/docs/core-concepts/link-content-relationship",
|
|
35
|
+
Embed: "https://prismic.io/docs/core-concepts/embed",
|
|
36
|
+
GeoPoint: "https://prismic.io/docs/core-concepts/geopoint",
|
|
37
|
+
Group: "https://prismic.io/docs/core-concepts/group",
|
|
38
|
+
IntegrationFields: "https://prismic.io/docs/core-concepts/integration-fields",
|
|
39
|
+
Slices: "https://prismic.io/docs/core-concepts/slices"
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const CustomTypeModelFieldType = {
|
|
43
|
+
Boolean: "Boolean",
|
|
44
|
+
Color: "Color",
|
|
45
|
+
Date: "Date",
|
|
46
|
+
Embed: "Embed",
|
|
47
|
+
GeoPoint: "GeoPoint",
|
|
48
|
+
Group: "Group",
|
|
49
|
+
Image: "Image",
|
|
50
|
+
IntegrationFields: "IntegrationFields",
|
|
51
|
+
Link: "Link",
|
|
52
|
+
Number: "Number",
|
|
53
|
+
Select: "Select",
|
|
54
|
+
Slices: "Slices",
|
|
55
|
+
StructuredText: "StructuredText",
|
|
56
|
+
Text: "Text",
|
|
57
|
+
Timestamp: "Timestamp",
|
|
58
|
+
UID: "UID"
|
|
59
|
+
};
|
|
60
|
+
const CustomTypeModelLinkSelectType = {
|
|
61
|
+
Document: "document",
|
|
62
|
+
Media: "media"
|
|
63
|
+
};
|
|
64
|
+
const CustomTypeModelSliceType = {
|
|
65
|
+
Slice: "Slice",
|
|
66
|
+
SharedSlice: "SharedSlice"
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const isCustomTypeModelField = (model) => {
|
|
70
|
+
return typeof model === "object" && model !== null && "type" in model && "config" in model;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const isCustomTypeModelSlice = (model) => {
|
|
74
|
+
return typeof model === "object" && model !== null && "non-repeat" in model && "repeat" in model;
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const isSharedSliceModel$1 = (model) => {
|
|
78
|
+
return typeof model === "object" && model !== null && "variations" in model;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
const getAPIIDPath = (config) => {
|
|
82
|
+
return config.path.map((element, i) => {
|
|
83
|
+
if (isCustomTypeModelField(element.model) && (element.model.type === CustomTypeModelFieldType.Group || element.model.type === CustomTypeModelFieldType.Slices)) {
|
|
84
|
+
return `${element.id}[]`;
|
|
85
|
+
} else {
|
|
86
|
+
if (element.id === "items") {
|
|
87
|
+
const previousElement = config.path[i - 1];
|
|
88
|
+
if (isCustomTypeModelSlice(previousElement.model) || isSharedSliceModel$1(previousElement.model)) {
|
|
89
|
+
return `${element.id}[]`;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return element.id;
|
|
93
|
+
}
|
|
94
|
+
}).join(".");
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const getFieldDocumentationURL = (config) => {
|
|
98
|
+
return FIELD_DOCUMENTATION_URLS[config.model.type];
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const isCustomTypeModel$1 = (model) => {
|
|
102
|
+
return typeof model === "object" && model !== null && "json" in model;
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const getHumanReadableModelName = (config) => {
|
|
106
|
+
if (isCustomTypeModel$1(config.model)) {
|
|
107
|
+
return config.model.label;
|
|
108
|
+
} else if (isSharedSliceModel$1(config.model)) {
|
|
109
|
+
return config.model.name;
|
|
110
|
+
} else if (isCustomTypeModelField(config.model) && "label" in config.model.config) {
|
|
111
|
+
return config.model.config.label;
|
|
112
|
+
} else if (isCustomTypeModelSlice(config.model)) {
|
|
113
|
+
return config.model.fieldset;
|
|
114
|
+
} else {
|
|
115
|
+
return `Slice Zone (\`${config.id}\`)`;
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
const getHumanReadableFieldPath = (config) => {
|
|
120
|
+
return config.path.map((element) => {
|
|
121
|
+
if (element.label) {
|
|
122
|
+
return element.label;
|
|
123
|
+
} else if (element.model) {
|
|
124
|
+
return getHumanReadableModelName({
|
|
125
|
+
id: element.id,
|
|
126
|
+
model: element.model
|
|
127
|
+
});
|
|
128
|
+
} else {
|
|
129
|
+
return element.id;
|
|
130
|
+
}
|
|
131
|
+
}).join(" \u2192 ");
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const getHumanReadableFieldType = (config) => {
|
|
135
|
+
switch (config.model.type) {
|
|
136
|
+
case "StructuredText": {
|
|
137
|
+
const isTitleField = "single" in config.model.config && config.model.config.single.split(",").every((blockType) => /heading/.test(blockType));
|
|
138
|
+
return isTitleField ? "Title" : "Rich Text";
|
|
139
|
+
}
|
|
140
|
+
case "IntegrationFields": {
|
|
141
|
+
return `Integration Fields (Catalog: \`${config.model.config.catalog}\`)`;
|
|
142
|
+
}
|
|
143
|
+
case "Link": {
|
|
144
|
+
switch (config.model.config.select) {
|
|
145
|
+
case CustomTypeModelLinkSelectType.Document: {
|
|
146
|
+
return "Content Relationship";
|
|
147
|
+
}
|
|
148
|
+
case CustomTypeModelLinkSelectType.Media: {
|
|
149
|
+
return "Link to Media";
|
|
150
|
+
}
|
|
151
|
+
default: {
|
|
152
|
+
return "Link";
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
case "Slices": {
|
|
157
|
+
return "Slice Zone";
|
|
158
|
+
}
|
|
159
|
+
default: {
|
|
160
|
+
return config.model.type;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const writeFieldDocsDescription = (config) => {
|
|
166
|
+
if (config.description) {
|
|
167
|
+
config.writer.writeLine(config.description);
|
|
168
|
+
}
|
|
169
|
+
config.writer.blankLineIfLastNot();
|
|
170
|
+
if (config.fieldType) {
|
|
171
|
+
config.writer.writeLine(`- **Field Type**: ${config.fieldType}`);
|
|
172
|
+
}
|
|
173
|
+
if (config.placeholder) {
|
|
174
|
+
config.writer.writeLine(`- **Placeholder**: ${config.placeholder}`);
|
|
175
|
+
}
|
|
176
|
+
if (config.defaultValue !== void 0) {
|
|
177
|
+
const stringifiedDefaultValue = typeof config.defaultValue === "boolean" ? `${config.defaultValue}` : config.defaultValue;
|
|
178
|
+
config.writer.writeLine(`- **Default Value**: ${stringifiedDefaultValue}`);
|
|
179
|
+
}
|
|
180
|
+
if (config.apiIDPath) {
|
|
181
|
+
config.writer.writeLine(`- **API ID Path**: ${config.apiIDPath}`);
|
|
182
|
+
}
|
|
183
|
+
if (config.documentationURL) {
|
|
184
|
+
config.writer.writeLine(`- **Documentation**: ${config.documentationURL}`);
|
|
185
|
+
}
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const buildFieldDocs = (config) => {
|
|
189
|
+
return [
|
|
190
|
+
{
|
|
191
|
+
description: (writer) => {
|
|
192
|
+
const name = getHumanReadableModelName({
|
|
193
|
+
id: config.id,
|
|
194
|
+
model: config.model
|
|
195
|
+
});
|
|
196
|
+
const humanReadablePath = getHumanReadableFieldPath({
|
|
197
|
+
path: config.path
|
|
198
|
+
});
|
|
199
|
+
const fieldType = getHumanReadableFieldType({
|
|
200
|
+
model: config.model
|
|
201
|
+
});
|
|
202
|
+
const placeholder = "placeholder" in config.model.config && config.model.config.placeholder ? config.model.config.placeholder : `*None*`;
|
|
203
|
+
const defaultValue = "default_value" in config.model.config ? config.model.config.default_value : void 0;
|
|
204
|
+
const apiIDPath = getAPIIDPath({
|
|
205
|
+
path: [...config.path, { id: config.id, model: config.model }]
|
|
206
|
+
});
|
|
207
|
+
writeFieldDocsDescription({
|
|
208
|
+
writer,
|
|
209
|
+
description: `${name} field in *${humanReadablePath}*`,
|
|
210
|
+
fieldType,
|
|
211
|
+
placeholder,
|
|
212
|
+
defaultValue,
|
|
213
|
+
apiIDPath,
|
|
214
|
+
documentationURL: getFieldDocumentationURL({ model: config.model })
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
];
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
const pascalCase = (input) => pascalCase$1(input, {
|
|
222
|
+
transform: pascalCaseTransformMerge
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
const buildSharedSliceInterfaceName = (config) => {
|
|
226
|
+
return pascalCase(`${config.id} Slice`);
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
const addInterfacePropertyFromField = (config) => {
|
|
230
|
+
switch (config.model.type) {
|
|
231
|
+
case "UID": {
|
|
232
|
+
break;
|
|
233
|
+
}
|
|
234
|
+
case "Boolean": {
|
|
235
|
+
config.interface.addProperty({
|
|
236
|
+
name: config.id,
|
|
237
|
+
type: "prismicT.BooleanField",
|
|
238
|
+
docs: buildFieldDocs({
|
|
239
|
+
id: config.id,
|
|
240
|
+
model: config.model,
|
|
241
|
+
path: config.path
|
|
242
|
+
})
|
|
243
|
+
});
|
|
244
|
+
break;
|
|
245
|
+
}
|
|
246
|
+
case "Color": {
|
|
247
|
+
config.interface.addProperty({
|
|
248
|
+
name: config.id,
|
|
249
|
+
type: "prismicT.ColorField",
|
|
250
|
+
docs: buildFieldDocs({
|
|
251
|
+
id: config.id,
|
|
252
|
+
model: config.model,
|
|
253
|
+
path: config.path
|
|
254
|
+
})
|
|
255
|
+
});
|
|
256
|
+
break;
|
|
257
|
+
}
|
|
258
|
+
case "Date": {
|
|
259
|
+
config.interface.addProperty({
|
|
260
|
+
name: config.id,
|
|
261
|
+
type: "prismicT.DateField",
|
|
262
|
+
docs: buildFieldDocs({
|
|
263
|
+
id: config.id,
|
|
264
|
+
model: config.model,
|
|
265
|
+
path: config.path
|
|
266
|
+
})
|
|
267
|
+
});
|
|
268
|
+
break;
|
|
269
|
+
}
|
|
270
|
+
case "Embed": {
|
|
271
|
+
const providerTypes = [];
|
|
272
|
+
if (config.fieldConfigs.embed?.providerTypes) {
|
|
273
|
+
for (const providerType in config.fieldConfigs.embed?.providerTypes) {
|
|
274
|
+
const configuredProviderType = config.fieldConfigs.embed?.providerTypes[providerType];
|
|
275
|
+
providerTypes.push(`({ provider_name: "${providerType}" } & ${configuredProviderType})`);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
config.interface.addProperty({
|
|
279
|
+
name: config.id,
|
|
280
|
+
type: providerTypes.length > 0 ? `prismicT.EmbedField<prismicT.AnyOEmbed & prismicT.OEmbedExtra & (${providerTypes.join(" | ")})>` : "prismicT.EmbedField",
|
|
281
|
+
docs: buildFieldDocs({
|
|
282
|
+
id: config.id,
|
|
283
|
+
model: config.model,
|
|
284
|
+
path: config.path
|
|
285
|
+
})
|
|
286
|
+
});
|
|
287
|
+
break;
|
|
288
|
+
}
|
|
289
|
+
case "GeoPoint": {
|
|
290
|
+
config.interface.addProperty({
|
|
291
|
+
name: config.id,
|
|
292
|
+
type: "prismicT.GeoPointField",
|
|
293
|
+
docs: buildFieldDocs({
|
|
294
|
+
id: config.id,
|
|
295
|
+
model: config.model,
|
|
296
|
+
path: config.path
|
|
297
|
+
})
|
|
298
|
+
});
|
|
299
|
+
break;
|
|
300
|
+
}
|
|
301
|
+
case "Image": {
|
|
302
|
+
if (config.model.config.thumbnails.length > 0) {
|
|
303
|
+
const thumbnailNames = config.model.config.thumbnails.map((thumbnail) => `"${thumbnail.name}"`).join(" | ");
|
|
304
|
+
config.interface.addProperty({
|
|
305
|
+
name: config.id,
|
|
306
|
+
type: `prismicT.ImageField<${thumbnailNames}>`,
|
|
307
|
+
docs: buildFieldDocs({
|
|
308
|
+
id: config.id,
|
|
309
|
+
model: config.model,
|
|
310
|
+
path: config.path
|
|
311
|
+
})
|
|
312
|
+
});
|
|
313
|
+
} else {
|
|
314
|
+
config.interface.addProperty({
|
|
315
|
+
name: config.id,
|
|
316
|
+
type: "prismicT.ImageField<null>",
|
|
317
|
+
docs: buildFieldDocs({
|
|
318
|
+
id: config.id,
|
|
319
|
+
model: config.model,
|
|
320
|
+
path: config.path
|
|
321
|
+
})
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
break;
|
|
325
|
+
}
|
|
326
|
+
case "IntegrationFields": {
|
|
327
|
+
const catalogType = config.fieldConfigs.integrationFields?.catalogTypes?.[config.model.config.catalog];
|
|
328
|
+
config.interface.addProperty({
|
|
329
|
+
name: config.id,
|
|
330
|
+
type: catalogType ? `prismicT.IntegrationFields<${catalogType}>` : "prismicT.IntegrationFields",
|
|
331
|
+
docs: buildFieldDocs({
|
|
332
|
+
id: config.id,
|
|
333
|
+
model: config.model,
|
|
334
|
+
path: config.path
|
|
335
|
+
})
|
|
336
|
+
});
|
|
337
|
+
break;
|
|
338
|
+
}
|
|
339
|
+
case "Link": {
|
|
340
|
+
switch (config.model.config.select) {
|
|
341
|
+
case CustomTypeModelLinkSelectType.Document: {
|
|
342
|
+
config.interface.addProperty({
|
|
343
|
+
name: config.id,
|
|
344
|
+
type: config.model.config.customtypes && config.model.config.customtypes.length > 0 ? `prismicT.RelationField<${config.model.config.customtypes.map((type) => `"${type}"`).join(" | ")}>` : "prismicT.RelationField",
|
|
345
|
+
docs: buildFieldDocs({
|
|
346
|
+
id: config.id,
|
|
347
|
+
model: config.model,
|
|
348
|
+
path: config.path
|
|
349
|
+
})
|
|
350
|
+
});
|
|
351
|
+
break;
|
|
352
|
+
}
|
|
353
|
+
case CustomTypeModelLinkSelectType.Media: {
|
|
354
|
+
config.interface.addProperty({
|
|
355
|
+
name: config.id,
|
|
356
|
+
type: "prismicT.LinkToMediaField",
|
|
357
|
+
docs: buildFieldDocs({
|
|
358
|
+
id: config.id,
|
|
359
|
+
model: config.model,
|
|
360
|
+
path: config.path
|
|
361
|
+
})
|
|
362
|
+
});
|
|
363
|
+
break;
|
|
364
|
+
}
|
|
365
|
+
default: {
|
|
366
|
+
config.interface.addProperty({
|
|
367
|
+
name: config.id,
|
|
368
|
+
type: "prismicT.LinkField",
|
|
369
|
+
docs: buildFieldDocs({
|
|
370
|
+
id: config.id,
|
|
371
|
+
model: config.model,
|
|
372
|
+
path: config.path
|
|
373
|
+
})
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
break;
|
|
378
|
+
}
|
|
379
|
+
case "Number": {
|
|
380
|
+
config.interface.addProperty({
|
|
381
|
+
name: config.id,
|
|
382
|
+
type: "prismicT.NumberField",
|
|
383
|
+
docs: buildFieldDocs({
|
|
384
|
+
id: config.id,
|
|
385
|
+
model: config.model,
|
|
386
|
+
path: config.path
|
|
387
|
+
})
|
|
388
|
+
});
|
|
389
|
+
break;
|
|
390
|
+
}
|
|
391
|
+
case "StructuredText": {
|
|
392
|
+
const isTitleField = "single" in config.model.config && config.model.config.single.split(",").every((blockType) => /heading/.test(blockType));
|
|
393
|
+
if (isTitleField) {
|
|
394
|
+
config.interface.addProperty({
|
|
395
|
+
name: config.id,
|
|
396
|
+
type: "prismicT.TitleField",
|
|
397
|
+
docs: buildFieldDocs({
|
|
398
|
+
id: config.id,
|
|
399
|
+
model: config.model,
|
|
400
|
+
path: config.path
|
|
401
|
+
})
|
|
402
|
+
});
|
|
403
|
+
} else {
|
|
404
|
+
config.interface.addProperty({
|
|
405
|
+
name: config.id,
|
|
406
|
+
type: "prismicT.RichTextField",
|
|
407
|
+
docs: buildFieldDocs({
|
|
408
|
+
id: config.id,
|
|
409
|
+
model: config.model,
|
|
410
|
+
path: config.path
|
|
411
|
+
})
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
break;
|
|
415
|
+
}
|
|
416
|
+
case "Select": {
|
|
417
|
+
const options = config.model.config.options.map((option) => `"${option}"`).join(" | ");
|
|
418
|
+
const hasDefault = Boolean(config.model.config.default_value);
|
|
419
|
+
if (hasDefault) {
|
|
420
|
+
config.interface.addProperty({
|
|
421
|
+
name: config.id,
|
|
422
|
+
type: `prismicT.SelectField<${options}, "filled">`,
|
|
423
|
+
docs: buildFieldDocs({
|
|
424
|
+
id: config.id,
|
|
425
|
+
model: config.model,
|
|
426
|
+
path: config.path
|
|
427
|
+
})
|
|
428
|
+
});
|
|
429
|
+
} else {
|
|
430
|
+
config.interface.addProperty({
|
|
431
|
+
name: config.id,
|
|
432
|
+
type: `prismicT.SelectField<${options}>`,
|
|
433
|
+
docs: buildFieldDocs({
|
|
434
|
+
id: config.id,
|
|
435
|
+
model: config.model,
|
|
436
|
+
path: config.path
|
|
437
|
+
})
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
break;
|
|
441
|
+
}
|
|
442
|
+
case "Text": {
|
|
443
|
+
config.interface.addProperty({
|
|
444
|
+
name: config.id,
|
|
445
|
+
type: "prismicT.KeyTextField",
|
|
446
|
+
docs: buildFieldDocs({
|
|
447
|
+
id: config.id,
|
|
448
|
+
model: config.model,
|
|
449
|
+
path: config.path
|
|
450
|
+
})
|
|
451
|
+
});
|
|
452
|
+
break;
|
|
453
|
+
}
|
|
454
|
+
case "Timestamp": {
|
|
455
|
+
config.interface.addProperty({
|
|
456
|
+
name: config.id,
|
|
457
|
+
type: "prismicT.TimestampField",
|
|
458
|
+
docs: buildFieldDocs({
|
|
459
|
+
id: config.id,
|
|
460
|
+
model: config.model,
|
|
461
|
+
path: config.path
|
|
462
|
+
})
|
|
463
|
+
});
|
|
464
|
+
break;
|
|
465
|
+
}
|
|
466
|
+
case "Group": {
|
|
467
|
+
const itemInterface = config.sourceFile.addInterface({
|
|
468
|
+
name: pascalCase(`${config.path[0].id} Document Data ${config.id} Item`),
|
|
469
|
+
docs: [
|
|
470
|
+
{
|
|
471
|
+
description: (writer) => {
|
|
472
|
+
const humanReadablePath = getHumanReadableFieldPath({
|
|
473
|
+
path: [
|
|
474
|
+
...config.path,
|
|
475
|
+
{
|
|
476
|
+
id: config.id,
|
|
477
|
+
model: config.model
|
|
478
|
+
}
|
|
479
|
+
]
|
|
480
|
+
});
|
|
481
|
+
writer.writeLine(`Item in ${humanReadablePath}`);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
]
|
|
485
|
+
});
|
|
486
|
+
addInterfacePropertiesForFields({
|
|
487
|
+
interface: itemInterface,
|
|
488
|
+
sourceFile: config.sourceFile,
|
|
489
|
+
fields: config.model.config.fields,
|
|
490
|
+
path: [
|
|
491
|
+
...config.path,
|
|
492
|
+
{
|
|
493
|
+
id: config.id,
|
|
494
|
+
model: config.model
|
|
495
|
+
}
|
|
496
|
+
],
|
|
497
|
+
fieldConfigs: config.fieldConfigs
|
|
498
|
+
});
|
|
499
|
+
config.interface.addProperty({
|
|
500
|
+
name: config.id,
|
|
501
|
+
type: `prismicT.GroupField<Simplify<${itemInterface.getName()}>>`,
|
|
502
|
+
docs: buildFieldDocs({
|
|
503
|
+
id: config.id,
|
|
504
|
+
model: config.model,
|
|
505
|
+
path: config.path
|
|
506
|
+
})
|
|
507
|
+
});
|
|
508
|
+
break;
|
|
509
|
+
}
|
|
510
|
+
case "Slices": {
|
|
511
|
+
const choiceInterfaceNames = [];
|
|
512
|
+
for (const choiceId in config.model.config.choices) {
|
|
513
|
+
const choice = config.model.config.choices[choiceId];
|
|
514
|
+
if (choice.type === CustomTypeModelSliceType.SharedSlice) {
|
|
515
|
+
choiceInterfaceNames.push(buildSharedSliceInterfaceName({ id: choiceId }));
|
|
516
|
+
} else if (choice.type === CustomTypeModelSliceType.Slice) {
|
|
517
|
+
let primaryInterface;
|
|
518
|
+
if (Object.keys(choice["non-repeat"]).length > 0) {
|
|
519
|
+
primaryInterface = config.sourceFile.addInterface({
|
|
520
|
+
name: pascalCase(`${config.path[0].id} Document Data ${config.id} ${choiceId} Slice Primary`),
|
|
521
|
+
docs: [
|
|
522
|
+
{
|
|
523
|
+
description: (writer) => {
|
|
524
|
+
const humanReadablePath = getHumanReadableFieldPath({
|
|
525
|
+
path: [
|
|
526
|
+
...config.path,
|
|
527
|
+
{
|
|
528
|
+
id: config.id,
|
|
529
|
+
model: config.model
|
|
530
|
+
},
|
|
531
|
+
{
|
|
532
|
+
id: choiceId,
|
|
533
|
+
model: choice
|
|
534
|
+
},
|
|
535
|
+
{
|
|
536
|
+
id: "primary",
|
|
537
|
+
label: "Primary"
|
|
538
|
+
}
|
|
539
|
+
]
|
|
540
|
+
});
|
|
541
|
+
writer.writeLine(`Primary content in ${humanReadablePath}`);
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
]
|
|
545
|
+
});
|
|
546
|
+
addInterfacePropertiesForFields({
|
|
547
|
+
interface: primaryInterface,
|
|
548
|
+
sourceFile: config.sourceFile,
|
|
549
|
+
fields: choice["non-repeat"],
|
|
550
|
+
path: [
|
|
551
|
+
...config.path,
|
|
552
|
+
{
|
|
553
|
+
id: config.id,
|
|
554
|
+
model: config.model
|
|
555
|
+
},
|
|
556
|
+
{
|
|
557
|
+
id: choiceId,
|
|
558
|
+
model: choice
|
|
559
|
+
},
|
|
560
|
+
{
|
|
561
|
+
id: "primary",
|
|
562
|
+
label: "Primary"
|
|
563
|
+
}
|
|
564
|
+
],
|
|
565
|
+
fieldConfigs: config.fieldConfigs
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
let itemInterface;
|
|
569
|
+
if (Object.keys(choice.repeat).length > 0) {
|
|
570
|
+
itemInterface = config.sourceFile.addInterface({
|
|
571
|
+
name: pascalCase(`${config.path[0].id} Document Data ${config.id} ${choiceId} Slice Item`),
|
|
572
|
+
docs: [
|
|
573
|
+
{
|
|
574
|
+
description: (writer) => {
|
|
575
|
+
const humanReadablePath = getHumanReadableFieldPath({
|
|
576
|
+
path: [
|
|
577
|
+
...config.path,
|
|
578
|
+
{
|
|
579
|
+
id: config.id,
|
|
580
|
+
model: config.model
|
|
581
|
+
},
|
|
582
|
+
{
|
|
583
|
+
id: choiceId,
|
|
584
|
+
model: choice
|
|
585
|
+
},
|
|
586
|
+
{
|
|
587
|
+
id: "items",
|
|
588
|
+
label: "Items"
|
|
589
|
+
}
|
|
590
|
+
]
|
|
591
|
+
});
|
|
592
|
+
writer.writeLine(`Item in ${humanReadablePath}`);
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
]
|
|
596
|
+
});
|
|
597
|
+
addInterfacePropertiesForFields({
|
|
598
|
+
interface: itemInterface,
|
|
599
|
+
sourceFile: config.sourceFile,
|
|
600
|
+
fields: choice.repeat,
|
|
601
|
+
path: [
|
|
602
|
+
...config.path,
|
|
603
|
+
{
|
|
604
|
+
id: config.id,
|
|
605
|
+
model: config.model
|
|
606
|
+
},
|
|
607
|
+
{
|
|
608
|
+
id: choiceId,
|
|
609
|
+
model: choice
|
|
610
|
+
},
|
|
611
|
+
{
|
|
612
|
+
id: "items",
|
|
613
|
+
label: "Items"
|
|
614
|
+
}
|
|
615
|
+
],
|
|
616
|
+
fieldConfigs: config.fieldConfigs
|
|
617
|
+
});
|
|
618
|
+
}
|
|
619
|
+
const sliceType = config.sourceFile.addTypeAlias({
|
|
620
|
+
name: pascalCase(`${config.path[0].id} Document Data ${config.id} ${choiceId} Slice`),
|
|
621
|
+
type: `prismicT.Slice<"${choiceId}", ${primaryInterface ? `Simplify<${primaryInterface.getName()}>` : "Record<string, never>"}, ${itemInterface ? `Simplify<${itemInterface.getName()}>` : "never"}>`
|
|
622
|
+
});
|
|
623
|
+
choiceInterfaceNames.push(sliceType.getName());
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
const slicesType = config.sourceFile.addTypeAlias({
|
|
627
|
+
name: pascalCase(`${config.path[0].id} Document Data ${config.id} Slice`),
|
|
628
|
+
type: choiceInterfaceNames.length > 0 ? choiceInterfaceNames.join(" | ") : "never",
|
|
629
|
+
docs: [
|
|
630
|
+
{
|
|
631
|
+
description: (writer) => {
|
|
632
|
+
const humanReadablePath = getHumanReadableFieldPath({
|
|
633
|
+
path: [
|
|
634
|
+
...config.path,
|
|
635
|
+
{
|
|
636
|
+
id: config.id,
|
|
637
|
+
model: config.model
|
|
638
|
+
}
|
|
639
|
+
]
|
|
640
|
+
});
|
|
641
|
+
writer.writeLine(`Slice for *${humanReadablePath}*`);
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
]
|
|
645
|
+
});
|
|
646
|
+
config.interface.addProperty({
|
|
647
|
+
name: config.id,
|
|
648
|
+
type: `prismicT.SliceZone<${slicesType.getName()}>`,
|
|
649
|
+
docs: buildFieldDocs({
|
|
650
|
+
id: config.id,
|
|
651
|
+
model: config.model,
|
|
652
|
+
path: config.path
|
|
653
|
+
})
|
|
654
|
+
});
|
|
655
|
+
break;
|
|
656
|
+
}
|
|
657
|
+
default: {
|
|
658
|
+
config.interface.addProperty({
|
|
659
|
+
name: config.id,
|
|
660
|
+
type: "unknown",
|
|
661
|
+
docs: buildFieldDocs({
|
|
662
|
+
id: config.id,
|
|
663
|
+
model: config.model,
|
|
664
|
+
path: config.path
|
|
665
|
+
})
|
|
666
|
+
});
|
|
667
|
+
}
|
|
668
|
+
}
|
|
669
|
+
};
|
|
670
|
+
const addInterfacePropertiesForFields = (config) => {
|
|
671
|
+
for (const name in config.fields) {
|
|
672
|
+
addInterfacePropertyFromField({
|
|
673
|
+
...config,
|
|
674
|
+
id: name,
|
|
675
|
+
model: config.fields[name]
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
};
|
|
679
|
+
|
|
680
|
+
const collectCustomTypeFields = (model) => {
|
|
681
|
+
return Object.assign({}, ...Object.values(model.json));
|
|
682
|
+
};
|
|
683
|
+
const addTypeAliasForCustomType = ({
|
|
684
|
+
model,
|
|
685
|
+
sourceFile,
|
|
686
|
+
localeIDs,
|
|
687
|
+
fieldConfigs
|
|
688
|
+
}) => {
|
|
689
|
+
const { uid: uidField, ...fields } = collectCustomTypeFields(model);
|
|
690
|
+
const hasDataFields = Object.keys(fields).length > 0;
|
|
691
|
+
const hasUIDField = Boolean(uidField);
|
|
692
|
+
let dataInterface;
|
|
693
|
+
if (hasDataFields) {
|
|
694
|
+
dataInterface = sourceFile.addInterface({
|
|
695
|
+
name: pascalCase(`${model.id} Document Data`),
|
|
696
|
+
docs: [
|
|
697
|
+
{
|
|
698
|
+
description: `Content for ${model.label} documents`
|
|
699
|
+
}
|
|
700
|
+
]
|
|
701
|
+
});
|
|
702
|
+
addInterfacePropertiesForFields({
|
|
703
|
+
fields,
|
|
704
|
+
interface: dataInterface,
|
|
705
|
+
sourceFile,
|
|
706
|
+
path: [
|
|
707
|
+
{
|
|
708
|
+
id: model.id,
|
|
709
|
+
model
|
|
710
|
+
}
|
|
711
|
+
],
|
|
712
|
+
fieldConfigs
|
|
713
|
+
});
|
|
714
|
+
} else {
|
|
715
|
+
dataInterface = sourceFile.addTypeAlias({
|
|
716
|
+
name: pascalCase(`${model.id} Document Data`),
|
|
717
|
+
type: `Record<string, never>`,
|
|
718
|
+
docs: [
|
|
719
|
+
{
|
|
720
|
+
description: `Content for ${model.label} documents`
|
|
721
|
+
}
|
|
722
|
+
]
|
|
723
|
+
});
|
|
724
|
+
}
|
|
725
|
+
return sourceFile.addTypeAlias({
|
|
726
|
+
name: pascalCase(`${model.id} Document`),
|
|
727
|
+
typeParameters: [
|
|
728
|
+
{
|
|
729
|
+
name: "Lang",
|
|
730
|
+
constraint: "string",
|
|
731
|
+
default: localeIDs.length > 0 ? localeIDs.map((localeID) => `"${localeID}"`).join(" | ") : "string"
|
|
732
|
+
}
|
|
733
|
+
],
|
|
734
|
+
type: hasUIDField ? `prismicT.PrismicDocumentWithUID<Simplify<${dataInterface.getName()}>, "${model.id}", Lang>` : `prismicT.PrismicDocumentWithoutUID<Simplify<${dataInterface.getName()}>, "${model.id}", Lang>`,
|
|
735
|
+
docs: [
|
|
736
|
+
{
|
|
737
|
+
description: (writer) => {
|
|
738
|
+
writer.writeLine(`${model.label} document from Prismic`);
|
|
739
|
+
writer.blankLine();
|
|
740
|
+
writer.writeLine(`- **API ID**: \`${model.id}\``);
|
|
741
|
+
writer.writeLine(`- **Repeatable**: \`${model.repeatable}\``);
|
|
742
|
+
writer.writeLine(`- **Documentation**: ${CUSTOM_TYPES_DOCUMENTATION_URL}`);
|
|
743
|
+
},
|
|
744
|
+
tags: [
|
|
745
|
+
{
|
|
746
|
+
tagName: "typeParam",
|
|
747
|
+
text: "Lang - Language API ID of the document."
|
|
748
|
+
}
|
|
749
|
+
]
|
|
750
|
+
}
|
|
751
|
+
],
|
|
752
|
+
isExported: true
|
|
753
|
+
});
|
|
754
|
+
};
|
|
755
|
+
|
|
756
|
+
const addTypeAliasForSharedSlice = (config) => {
|
|
757
|
+
const variationTypeNames = [];
|
|
758
|
+
for (const variation of config.model.variations) {
|
|
759
|
+
let primaryInterface;
|
|
760
|
+
if (Object.keys(variation.primary).length > 0) {
|
|
761
|
+
primaryInterface = config.sourceFile.addInterface({
|
|
762
|
+
name: pascalCase(`${buildSharedSliceInterfaceName({ id: config.model.id })} ${variation.id} Primary`),
|
|
763
|
+
docs: [
|
|
764
|
+
{
|
|
765
|
+
description: (writer) => {
|
|
766
|
+
const humanReadablePath = getHumanReadableFieldPath({
|
|
767
|
+
path: [
|
|
768
|
+
{
|
|
769
|
+
id: config.model.id,
|
|
770
|
+
model: config.model
|
|
771
|
+
},
|
|
772
|
+
{
|
|
773
|
+
id: "primary",
|
|
774
|
+
label: "Primary"
|
|
775
|
+
}
|
|
776
|
+
]
|
|
777
|
+
});
|
|
778
|
+
writer.writeLine(`Primary content in ${humanReadablePath}`);
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
]
|
|
782
|
+
});
|
|
783
|
+
addInterfacePropertiesForFields({
|
|
784
|
+
interface: primaryInterface,
|
|
785
|
+
sourceFile: config.sourceFile,
|
|
786
|
+
fields: variation.primary,
|
|
787
|
+
path: [
|
|
788
|
+
{
|
|
789
|
+
id: config.model.id,
|
|
790
|
+
model: config.model
|
|
791
|
+
},
|
|
792
|
+
{
|
|
793
|
+
id: "primary",
|
|
794
|
+
label: "Primary"
|
|
795
|
+
}
|
|
796
|
+
],
|
|
797
|
+
fieldConfigs: config.fieldConfigs
|
|
798
|
+
});
|
|
799
|
+
}
|
|
800
|
+
let itemInterface;
|
|
801
|
+
if (Object.keys(variation.items).length > 0) {
|
|
802
|
+
itemInterface = config.sourceFile.addInterface({
|
|
803
|
+
name: pascalCase(`${buildSharedSliceInterfaceName({ id: config.model.id })} ${variation.id} Item`),
|
|
804
|
+
docs: [
|
|
805
|
+
{
|
|
806
|
+
description: (writer) => {
|
|
807
|
+
const humanReadablePath = getHumanReadableFieldPath({
|
|
808
|
+
path: [
|
|
809
|
+
{
|
|
810
|
+
id: config.model.id,
|
|
811
|
+
model: config.model
|
|
812
|
+
},
|
|
813
|
+
{
|
|
814
|
+
id: "items",
|
|
815
|
+
label: "Items"
|
|
816
|
+
}
|
|
817
|
+
]
|
|
818
|
+
});
|
|
819
|
+
writer.writeLine(`Item in ${humanReadablePath}`);
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
]
|
|
823
|
+
});
|
|
824
|
+
addInterfacePropertiesForFields({
|
|
825
|
+
interface: itemInterface,
|
|
826
|
+
sourceFile: config.sourceFile,
|
|
827
|
+
fields: variation.items,
|
|
828
|
+
path: [
|
|
829
|
+
{
|
|
830
|
+
id: config.model.id,
|
|
831
|
+
model: config.model
|
|
832
|
+
},
|
|
833
|
+
{
|
|
834
|
+
id: "items",
|
|
835
|
+
label: "Items"
|
|
836
|
+
}
|
|
837
|
+
],
|
|
838
|
+
fieldConfigs: config.fieldConfigs
|
|
839
|
+
});
|
|
840
|
+
}
|
|
841
|
+
const variationType = config.sourceFile.addTypeAlias({
|
|
842
|
+
name: pascalCase(`${buildSharedSliceInterfaceName({
|
|
843
|
+
id: config.model.id
|
|
844
|
+
})} ${variation.id}`),
|
|
845
|
+
type: `prismicT.SharedSliceVariation<"${variation.id}", ${primaryInterface ? `Simplify<${primaryInterface.getName()}>` : "Record<string, never>"}, ${itemInterface ? `Simplify<${itemInterface.getName()}>` : "never"}>`,
|
|
846
|
+
docs: [
|
|
847
|
+
{
|
|
848
|
+
description: (writer) => {
|
|
849
|
+
writer.writeLine(`${variation.name} variation for ${config.model.name} Slice`);
|
|
850
|
+
writer.blankLine();
|
|
851
|
+
writer.writeLine(`- **API ID**: \`${variation.id}\``);
|
|
852
|
+
writer.writeLine(`- **Description**: \`${variation.description}\``);
|
|
853
|
+
writer.writeLine(`- **Documentation**: ${SHARED_SLICES_DOCUMENTATION_URL}`);
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
]
|
|
857
|
+
});
|
|
858
|
+
variationTypeNames.push(variationType.getName());
|
|
859
|
+
}
|
|
860
|
+
const variationsType = config.sourceFile.addTypeAlias({
|
|
861
|
+
name: pascalCase(`${config.model.id} Slice Variation`),
|
|
862
|
+
type: variationTypeNames.length > 0 ? variationTypeNames.join(" | ") : "never",
|
|
863
|
+
docs: [
|
|
864
|
+
{
|
|
865
|
+
description: (writer) => {
|
|
866
|
+
const humanReadablePath = getHumanReadableFieldPath({
|
|
867
|
+
path: [
|
|
868
|
+
{
|
|
869
|
+
id: config.model.id,
|
|
870
|
+
model: config.model
|
|
871
|
+
}
|
|
872
|
+
]
|
|
873
|
+
});
|
|
874
|
+
writer.writeLine(`Slice variation for *${humanReadablePath}*`);
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
]
|
|
878
|
+
});
|
|
879
|
+
return config.sourceFile.addTypeAlias({
|
|
880
|
+
name: pascalCase(buildSharedSliceInterfaceName({
|
|
881
|
+
id: config.model.id
|
|
882
|
+
})),
|
|
883
|
+
type: `prismicT.SharedSlice<"${config.model.id}", ${variationsType.getName()}>`,
|
|
884
|
+
docs: [
|
|
885
|
+
{
|
|
886
|
+
description: (writer) => {
|
|
887
|
+
writer.writeLine(`${config.model.name} Shared Slice`);
|
|
888
|
+
writer.blankLine();
|
|
889
|
+
writer.writeLine(`- **API ID**: \`${config.model.id}\``);
|
|
890
|
+
writer.writeLine(`- **Description**: \`${config.model.description}\``);
|
|
891
|
+
writer.writeLine(`- **Documentation**: ${SHARED_SLICES_DOCUMENTATION_URL}`);
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
],
|
|
895
|
+
isExported: true
|
|
896
|
+
});
|
|
897
|
+
};
|
|
898
|
+
|
|
899
|
+
const getSourceFileText = (sourceFile) => {
|
|
900
|
+
const text = sourceFile.print().replace(new RegExp(BLANK_LINE_IDENTIFIER, "g"), "");
|
|
901
|
+
return text;
|
|
902
|
+
};
|
|
903
|
+
|
|
904
|
+
const generateTypes = (config = {}) => {
|
|
905
|
+
const project = new Project({
|
|
906
|
+
useInMemoryFileSystem: true
|
|
907
|
+
});
|
|
908
|
+
const sourceFile = project.createSourceFile("types.d.ts");
|
|
909
|
+
sourceFile.addImportDeclaration({
|
|
910
|
+
moduleSpecifier: "@prismicio/types",
|
|
911
|
+
namespaceImport: "prismicT",
|
|
912
|
+
isTypeOnly: true,
|
|
913
|
+
leadingTrivia: NON_EDITABLE_FILE_HEADER
|
|
914
|
+
});
|
|
915
|
+
sourceFile.addStatements(BLANK_LINE_IDENTIFIER);
|
|
916
|
+
sourceFile.addTypeAlias({
|
|
917
|
+
name: "Simplify",
|
|
918
|
+
typeParameters: [
|
|
919
|
+
{
|
|
920
|
+
name: "T"
|
|
921
|
+
}
|
|
922
|
+
],
|
|
923
|
+
type: `{ [KeyType in keyof T]: T[KeyType] }`
|
|
924
|
+
});
|
|
925
|
+
if (config.customTypeModels) {
|
|
926
|
+
for (const model of config.customTypeModels) {
|
|
927
|
+
addTypeAliasForCustomType({
|
|
928
|
+
model,
|
|
929
|
+
sourceFile,
|
|
930
|
+
localeIDs: config.localeIDs || [],
|
|
931
|
+
fieldConfigs: config.fieldConfigs || {}
|
|
932
|
+
});
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
if (config.sharedSliceModels) {
|
|
936
|
+
for (const model of config.sharedSliceModels) {
|
|
937
|
+
addTypeAliasForSharedSlice({
|
|
938
|
+
model,
|
|
939
|
+
sourceFile,
|
|
940
|
+
fieldConfigs: config.fieldConfigs || {}
|
|
941
|
+
});
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
return getSourceFileText(sourceFile);
|
|
945
|
+
};
|
|
946
|
+
|
|
947
|
+
const configSchema = Joi.object({
|
|
948
|
+
repositoryName: Joi.string(),
|
|
949
|
+
accessToken: Joi.string(),
|
|
950
|
+
customTypesAPIToken: Joi.string(),
|
|
951
|
+
output: Joi.string(),
|
|
952
|
+
locales: Joi.alternatives(Joi.array().items(Joi.string().required()), Joi.object({
|
|
953
|
+
ids: Joi.array().items(Joi.string().required()),
|
|
954
|
+
fetchFromRepository: Joi.boolean()
|
|
955
|
+
})),
|
|
956
|
+
models: Joi.alternatives(Joi.array().items(Joi.string().required()), Joi.object({
|
|
957
|
+
files: Joi.array().items(Joi.string().required()),
|
|
958
|
+
fetchFromRepository: Joi.boolean()
|
|
959
|
+
})),
|
|
960
|
+
fields: Joi.object({
|
|
961
|
+
embed: Joi.object({
|
|
962
|
+
providerTypes: Joi.object().pattern(Joi.string(), Joi.string().required())
|
|
963
|
+
}),
|
|
964
|
+
integrationFields: Joi.object({
|
|
965
|
+
catalogTypes: Joi.object().pattern(Joi.string(), Joi.string().required())
|
|
966
|
+
})
|
|
967
|
+
})
|
|
968
|
+
}).when(Joi.object({
|
|
969
|
+
locales: Joi.object({
|
|
970
|
+
fetchFromRepository: Joi.valid(true)
|
|
971
|
+
})
|
|
972
|
+
}), {
|
|
973
|
+
then: Joi.object({
|
|
974
|
+
repositoryName: Joi.required()
|
|
975
|
+
})
|
|
976
|
+
}).when(Joi.object({
|
|
977
|
+
models: Joi.object({
|
|
978
|
+
fetchFromRepository: Joi.valid(true)
|
|
979
|
+
})
|
|
980
|
+
}), {
|
|
981
|
+
then: Joi.object({
|
|
982
|
+
repositoryName: Joi.required(),
|
|
983
|
+
customTypesAPIToken: Joi.required()
|
|
984
|
+
})
|
|
985
|
+
});
|
|
986
|
+
|
|
987
|
+
const loadLocaleIDs = async (config) => {
|
|
988
|
+
const localeIDs = new Set(config.localeIDs || []);
|
|
989
|
+
if ("repositoryName" in config && config.fetchFromRepository) {
|
|
990
|
+
const client = prismic.createClient(config.repositoryName, {
|
|
991
|
+
accessToken: config.accessToken,
|
|
992
|
+
fetch
|
|
993
|
+
});
|
|
994
|
+
const repository = await client.getRepository();
|
|
995
|
+
for (const language of repository.languages) {
|
|
996
|
+
localeIDs.add(language.id);
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
return [...localeIDs];
|
|
1000
|
+
};
|
|
1001
|
+
|
|
1002
|
+
const isCustomTypeModel = (input) => {
|
|
1003
|
+
return typeof input === "object" && input !== null && "json" in input;
|
|
1004
|
+
};
|
|
1005
|
+
const isSharedSliceModel = (input) => {
|
|
1006
|
+
return typeof input === "object" && input !== null && "variations" in input;
|
|
1007
|
+
};
|
|
1008
|
+
const readJSONFromGlob = async (globs) => {
|
|
1009
|
+
const paths = await fg(globs.split(",").map((path) => path.trim()));
|
|
1010
|
+
return paths.map((path) => {
|
|
1011
|
+
const raw = readFileSync(path, "utf8");
|
|
1012
|
+
return JSON.parse(raw);
|
|
1013
|
+
});
|
|
1014
|
+
};
|
|
1015
|
+
const loadModels = async (config) => {
|
|
1016
|
+
const customTypeModels = {};
|
|
1017
|
+
const sharedSliceModels = {};
|
|
1018
|
+
if ("customTypesAPIToken" in config) {
|
|
1019
|
+
const customTypesClient = prismicCT.createClient({
|
|
1020
|
+
repositoryName: config.repositoryName,
|
|
1021
|
+
token: config.customTypesAPIToken,
|
|
1022
|
+
fetch
|
|
1023
|
+
});
|
|
1024
|
+
if (config.fetchFromRepository) {
|
|
1025
|
+
const [remoteCustomTypeModels, remoteSharedSliceModels] = await Promise.all([
|
|
1026
|
+
customTypesClient.getAll(),
|
|
1027
|
+
customTypesClient.getAllSharedSlices()
|
|
1028
|
+
]);
|
|
1029
|
+
for (const customTypeModel of remoteCustomTypeModels) {
|
|
1030
|
+
customTypeModels[customTypeModel.id] = customTypeModel;
|
|
1031
|
+
}
|
|
1032
|
+
for (const sharedSliceModel of remoteSharedSliceModels) {
|
|
1033
|
+
sharedSliceModels[sharedSliceModel.id] = sharedSliceModel;
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
if (config.localPaths) {
|
|
1038
|
+
const models = (await Promise.all(config.localPaths.map((glob) => readJSONFromGlob(glob)))).flat();
|
|
1039
|
+
for (const model of models) {
|
|
1040
|
+
if (isCustomTypeModel(model)) {
|
|
1041
|
+
customTypeModels[model.id] = model;
|
|
1042
|
+
} else if (isSharedSliceModel(model)) {
|
|
1043
|
+
sharedSliceModels[model.id] = model;
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
return {
|
|
1048
|
+
customTypeModels: Object.values(customTypeModels),
|
|
1049
|
+
sharedSliceModels: Object.values(sharedSliceModels)
|
|
1050
|
+
};
|
|
1051
|
+
};
|
|
1052
|
+
|
|
1053
|
+
const jiti = _jiti(process.cwd());
|
|
1054
|
+
const DEFAULT_CONFIG_PATHS = [
|
|
1055
|
+
"prismicCodegen.config.ts",
|
|
1056
|
+
"prismicCodegen.config.js"
|
|
1057
|
+
];
|
|
1058
|
+
const loadConfig = (config) => {
|
|
1059
|
+
if (config.path) {
|
|
1060
|
+
if (existsSync(config.path)) {
|
|
1061
|
+
return jiti(config.path);
|
|
1062
|
+
} else {
|
|
1063
|
+
throw new Error(`Config file does not exist: ${config.path}`);
|
|
1064
|
+
}
|
|
1065
|
+
} else {
|
|
1066
|
+
for (const configPath of DEFAULT_CONFIG_PATHS) {
|
|
1067
|
+
if (existsSync(configPath)) {
|
|
1068
|
+
const mod = jiti(resolve(configPath));
|
|
1069
|
+
return "default" in mod ? mod.default : mod;
|
|
1070
|
+
}
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
return {};
|
|
1074
|
+
};
|
|
1075
|
+
|
|
1076
|
+
const cli = meow(`
|
|
1077
|
+
Usage:
|
|
1078
|
+
prismic-ts-codegen [options...]
|
|
1079
|
+
prismic-ts-codegen init [options...]
|
|
1080
|
+
|
|
1081
|
+
Commands:
|
|
1082
|
+
init [options]
|
|
1083
|
+
|
|
1084
|
+
Options:
|
|
1085
|
+
-c, --config <path> Path to a prismic-ts-codegen configuration file.
|
|
1086
|
+
`, {
|
|
1087
|
+
importMeta: import.meta,
|
|
1088
|
+
flags: {
|
|
1089
|
+
config: {
|
|
1090
|
+
type: "string",
|
|
1091
|
+
alias: "c",
|
|
1092
|
+
isRequired: false
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
});
|
|
1096
|
+
const main = async () => {
|
|
1097
|
+
if (cli.input[0] === "init") {
|
|
1098
|
+
const configPath = cli.flags.config || "prismicCodegen.config.ts";
|
|
1099
|
+
if (existsSync(configPath)) {
|
|
1100
|
+
console.info(`
|
|
1101
|
+
${configPath} already exists.`);
|
|
1102
|
+
} else {
|
|
1103
|
+
let contents = "";
|
|
1104
|
+
if (existsSync("sm.json")) {
|
|
1105
|
+
contents = stripIndent`
|
|
1106
|
+
import type { Config } from "prismic-ts-codegen";
|
|
1107
|
+
|
|
1108
|
+
const config: Config = {
|
|
1109
|
+
output: "./types.generated.ts",
|
|
1110
|
+
|
|
1111
|
+
models: ["./customtypes/**/index.json", "./slices/**/model.json"],
|
|
1112
|
+
};
|
|
1113
|
+
|
|
1114
|
+
export default config;
|
|
1115
|
+
`;
|
|
1116
|
+
} else {
|
|
1117
|
+
contents = stripIndent`
|
|
1118
|
+
import type { Config } from "prismic-ts-codegen";
|
|
1119
|
+
|
|
1120
|
+
const config: Config = {
|
|
1121
|
+
output: "./types.generated.ts",
|
|
1122
|
+
};
|
|
1123
|
+
|
|
1124
|
+
export default config;
|
|
1125
|
+
`;
|
|
1126
|
+
}
|
|
1127
|
+
writeFileSync(configPath, contents);
|
|
1128
|
+
console.info(`
|
|
1129
|
+
Created prismic-ts-codegen config file: ${configPath}`);
|
|
1130
|
+
}
|
|
1131
|
+
} else {
|
|
1132
|
+
const unvalidatedConfig = loadConfig({ path: cli.flags.config });
|
|
1133
|
+
const { value: config, error } = configSchema.validate(unvalidatedConfig);
|
|
1134
|
+
if (config && !error) {
|
|
1135
|
+
const { customTypeModels, sharedSliceModels } = await loadModels({
|
|
1136
|
+
localPaths: Array.isArray(config.models) ? config.models : config.models?.files,
|
|
1137
|
+
repositoryName: config.repositoryName,
|
|
1138
|
+
customTypesAPIToken: config.customTypesAPIToken,
|
|
1139
|
+
fetchFromRepository: config.models && "fetchFromRepository" in config.models && config.models.fetchFromRepository
|
|
1140
|
+
});
|
|
1141
|
+
const localeIDs = await loadLocaleIDs({
|
|
1142
|
+
localeIDs: Array.isArray(config.locales) ? config.locales : config.locales?.ids,
|
|
1143
|
+
repositoryName: config.repositoryName,
|
|
1144
|
+
accessToken: config.accessToken,
|
|
1145
|
+
fetchFromRepository: config.locales && "fetchFromRepository" in config.locales && config.locales.fetchFromRepository
|
|
1146
|
+
});
|
|
1147
|
+
const types = generateTypes({
|
|
1148
|
+
customTypeModels,
|
|
1149
|
+
sharedSliceModels,
|
|
1150
|
+
localeIDs
|
|
1151
|
+
});
|
|
1152
|
+
if (config.output) {
|
|
1153
|
+
writeFileSync(resolve(config.output), types);
|
|
1154
|
+
} else {
|
|
1155
|
+
process.stdout.write(types + "\n");
|
|
1156
|
+
}
|
|
1157
|
+
} else {
|
|
1158
|
+
if (error) {
|
|
1159
|
+
console.error(error.message);
|
|
1160
|
+
return;
|
|
1161
|
+
}
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
};
|
|
1165
|
+
main().catch((error) => console.error(error));
|
|
1166
|
+
//# sourceMappingURL=cli.mjs.map
|