Skip to content

Commit

Permalink
feat: integrate generated types into @prismicio/client automatically (
Browse files Browse the repository at this point in the history
#14)

* feat: add ability to generate `@prismicio/client` CreateClient interface

* fix: enable module augmentation by default in the CLI

* chore: rebuild package-lock.json

* feat: replace `repositoryName`-specific `@prismicio/client` integration with global `string` integration

* refactor: remove unused code

* docs: add `clientIntegration` option to README example

* fix: only add AllDocumentTypes if at least one Custom Type model is provided

* feat: add CLI output on success

* fix: allow empty `models` array
  • Loading branch information
angeloashmore authored Jun 22, 2022
1 parent cf52d58 commit e0d47ab
Show file tree
Hide file tree
Showing 8 changed files with 236 additions and 56 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ const config: Config = {

output: "./types.generated.ts",

clientIntegration: {
includeCreateClientInterface: true,
},

locales: {
ids: ["en-us", "fr-fr", "en-gb"],
fetchFromRepository: true,
Expand Down
66 changes: 40 additions & 26 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@
"peerDependencies": {
"@prismicio/types": "^0.1.25"
},
"optionalDependencies": {
"@prismicio/client": "^6.6"
},
"engines": {
"node": ">=12.7.0"
},
Expand Down
45 changes: 16 additions & 29 deletions src/cli/configSchema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,24 @@ import Joi from "joi";
import { Config } from "./types";

export const configSchema = Joi.object<Config>({
repositoryName: Joi.string(),
repositoryName: Joi.string()
.when("locales.fetchFromRepository", {
is: true,
then: Joi.required(),
})
.when("models.fetchFromRepository", {
is: true,
then: Joi.required(),
}),
accessToken: Joi.string(),
customTypesAPIToken: Joi.string(),

output: Joi.string(),

clientIntegration: {
includeCreateClientInterface: Joi.boolean,
},

locales: Joi.alternatives(
Joi.array().items(Joi.string().required()),
Joi.object({
Expand All @@ -18,9 +30,9 @@ export const configSchema = Joi.object<Config>({
),

models: Joi.alternatives(
Joi.array().items(Joi.string().required()),
Joi.array().items(Joi.string()),
Joi.object({
files: Joi.array().items(Joi.string().required()),
files: Joi.array().items(Joi.string()),
fetchFromRepository: Joi.boolean(),
}),
),
Expand All @@ -36,29 +48,4 @@ export const configSchema = Joi.object<Config>({
catalogTypes: Joi.object().pattern(Joi.string(), Joi.string().required()),
}),
}),
})
.when(
Joi.object({
locales: Joi.object({
fetchFromRepository: Joi.valid(true),
}),
}),
{
then: Joi.object({
repositoryName: Joi.required(),
}),
},
)
.when(
Joi.object({
models: Joi.object({
fetchFromRepository: Joi.valid(true),
}),
}),
{
then: Joi.object({
repositoryName: Joi.required(),
customTypesAPIToken: Joi.required(),
}),
},
);
});
18 changes: 18 additions & 0 deletions src/cli/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,14 +101,32 @@ const main = async () => {
config.locales.fetchFromRepository,
});

const hasCustomTypeModels = customTypeModels.length > 0;

const types = generateTypes({
customTypeModels,
sharedSliceModels,
localeIDs,
clientIntegration: {
includeCreateClientInterface: hasCustomTypeModels
? config.clientIntegration?.includeCreateClientInterface ?? true
: false,
},
});

if (
config.clientIntegration?.includeCreateClientInterface &&
!hasCustomTypeModels
) {
console.info(
"[INFO]: prismic-ts-codegen was configured to automatically integrate with `@prismicio/client`, but the integration was generated because no Custom Type models were found. Automatic integration requires at least one Custom Type model.",
);
}

if (config.output) {
writeFileSync(resolvePath(config.output), types);

console.info(`\nGenerated types in: ${config.output}`);
} else {
process.stdout.write(types + "\n");
}
Expand Down
21 changes: 21 additions & 0 deletions src/cli/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,27 @@ export type Config = {
*/
output?: string;

/**
* Configuration for automatic `@prismicio/client` integration.
*/
clientIntegration?: {
/**
* Determines if a `@prismicio/client` integration with automatic typing
* should be included in the output.
*
* If set to `true`, Prismic clients will automatically be typed with the
* generated Custom Types and Slices.
*
* **Note**: If your project queries content from multiple Prismic
* repositories, set `includeCreateClientInterface` to `false` and manually
* provide the generated `AllDocumentTypes` type to `@prismicio/client`'s
* `createClient()` function instead.
*
* @defaultValue `true`
*/
includeCreateClientInterface?: boolean;
};

/**
* Configuration for languages for the Prismic repository.
*
Expand Down
55 changes: 54 additions & 1 deletion src/generateTypes.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
import { Project } from "ts-morph";
import { Project, ModuleDeclarationKind } from "ts-morph";
import type { CustomTypeModel, SharedSliceModel } from "@prismicio/types";

import { BLANK_LINE_IDENTIFIER, NON_EDITABLE_FILE_HEADER } from "./constants";
import { addTypeAliasForCustomType } from "./lib/addTypeAliasForCustomType";
import { addTypeAliasForSharedSlice } from "./lib/addTypeAliasForSharedSlice";
import { getSourceFileText } from "./lib/getSourceFileText";
import { FieldConfigs } from "./types";
import { pascalCase } from "./lib/pascalCase";

export type GenerateTypesConfig = {
customTypeModels?: CustomTypeModel[];
sharedSliceModels?: SharedSliceModel[];
localeIDs?: string[];
fieldConfigs?: FieldConfigs;
clientIntegration?: {
includeCreateClientInterface?: boolean;
};
};

export const generateTypes = (config: GenerateTypesConfig = {}) => {
Expand Down Expand Up @@ -49,6 +53,18 @@ export const generateTypes = (config: GenerateTypesConfig = {}) => {
fieldConfigs: config.fieldConfigs || {},
});
}

if (config.customTypeModels.length > 0) {
sourceFile.addTypeAlias({
name: "AllDocumentTypes",
type: config.customTypeModels
.map((customTypeModel) =>
pascalCase(`${customTypeModel.id} Document`),
)
.join(" | "),
isExported: true,
});
}
}

if (config.sharedSliceModels) {
Expand All @@ -61,5 +77,42 @@ export const generateTypes = (config: GenerateTypesConfig = {}) => {
}
}

if (config.clientIntegration?.includeCreateClientInterface) {
sourceFile.addImportDeclaration({
moduleSpecifier: "@prismicio/client",
namespaceImport: "prismic",
isTypeOnly: true,
});

const clientModuleDeclaration = sourceFile.addModule({
name: '"@prismicio/client"',
hasDeclareKeyword: true,
declarationKind: ModuleDeclarationKind.Module,
});

clientModuleDeclaration.addInterface({
name: "CreateClient",
callSignatures: [
{
parameters: [
{
name: "repositoryNameOrEndpoint",
type: "string",
},
{
name: "options",
type: "prismic.ClientConfig",
hasQuestionToken: true,
},
],
returnType:
(config.customTypeModels?.length || 0) > 0
? "prismic.Client<AllDocumentTypes>"
: "prismic.Client",
},
],
});
}

return getSourceFileText(sourceFile);
};
Loading

0 comments on commit e0d47ab

Please sign in to comment.