@baseplate-dev/react-generators
Version:
React Generators for Baseplate
203 lines • 10.6 kB
JavaScript
import { TsCodeUtils } from '@baseplate-dev/core-generators';
import { createGenerator, createGeneratorTask, createProviderType, } from '@baseplate-dev/sync';
import { pluralize } from 'inflection';
import path from 'node:path';
import { z } from 'zod';
import { reactApolloProvider } from '#src/generators/apollo/react-apollo/index.js';
import { reactRoutesProvider } from '#src/providers/routes.js';
import { lowerCaseFirst } from '#src/utils/case.js';
import { areFieldsIdentical, mergeGraphQLFragments, renderGraphQLFragment, renderGraphQLRoot, } from '#src/writers/graphql/index.js';
import { adminCrudSectionScope } from '../admin-crud-section/index.js';
const descriptorSchema = z.object({
modelId: z.string(),
modelName: z.string(),
});
export const adminCrudQueriesProvider = createProviderType('admin-crud-queries');
export const adminCrudQueriesGenerator = createGenerator({
name: 'admin/admin-crud-queries',
generatorFileUrl: import.meta.url,
descriptorSchema,
getInstanceName: (descriptor) => descriptor.modelName,
buildTasks: ({ modelName, modelId }) => ({
main: createGeneratorTask({
dependencies: {
reactApollo: reactApolloProvider,
reactRoutes: reactRoutesProvider,
},
exports: {
adminCrudQueries: adminCrudQueriesProvider.export(adminCrudSectionScope),
},
run({ reactApollo, reactRoutes }) {
const config = {
rowFields: [],
formFields: [],
};
const rowFragmentName = `${modelName}Row`;
const editFragmentName = `${modelName}Edit`;
const listQueryName = `Get${pluralize(modelName)}`;
const listFieldName = lowerCaseFirst(pluralize(modelName));
const editQueryName = `${editFragmentName}ById`;
const editFieldName = lowerCaseFirst(modelName);
const createFieldName = `create${modelName}`;
const createMutationName = `Create${modelName}`;
const updateFieldName = `update${modelName}`;
const updateMutationName = `Update${modelName}`;
const deleteFieldName = `delete${modelName}`;
const deleteMutationName = `Delete${modelName}`;
function getGeneratedImport(name) {
return TsCodeUtils.importFragment(name, reactApollo.getGeneratedFilePath());
}
function getGeneratedTypeImport(name) {
return TsCodeUtils.typeImportFragment(name, reactApollo.getGeneratedFilePath());
}
function getHookInfo(documentName, fieldName) {
return {
fieldName,
documentExpression: getGeneratedImport(documentName),
};
}
const queries = [];
const fragments = [];
const roots = [];
function createMutation(mutationName, fieldName, inputType, returnIdOnly) {
return renderGraphQLRoot({
type: 'mutation',
name: mutationName,
variables: [{ name: 'input', type: `${inputType}!` }],
fields: [
{
name: fieldName,
args: [
{
name: 'input',
value: { type: 'variable', variable: 'input' },
},
],
fields: [
{
name: editFieldName,
fields: [
returnIdOnly
? { name: 'id' }
: { type: 'spread', on: editFragmentName },
],
},
],
},
],
});
}
return {
providers: {
adminCrudQueries: {
setRowFields: (fields) => {
config.rowFields = fields;
},
setFormFields: (fields) => {
config.formFields = fields;
},
getRowFragmentExpression: () => getGeneratedTypeImport(`${rowFragmentName}Fragment`),
getEditFragmentExpression: () => getGeneratedTypeImport(`${editFragmentName}Fragment`),
getListQueryHookInfo: () => getHookInfo(`${listQueryName}Document`, listFieldName),
getEditQueryHookInfo: () => getHookInfo(`${editQueryName}Document`, editFieldName),
getCreateHookInfo: () => {
config.generateCreate = true;
return getHookInfo(`Create${modelName}Document`, createFieldName);
},
getUpdateHookInfo: () => {
config.generateUpdate = true;
return getHookInfo(`Update${modelName}Document`, updateFieldName);
},
getDeleteHookInfo: () => {
config.generateDelete = true;
return getHookInfo(`Delete${modelName}Document`, deleteFieldName);
},
getListDocumentExpression: () => getGeneratedImport(`${listQueryName}Document`),
addFragment: (fragment) => {
fragments.push(fragment);
},
addRoot: (root) => {
const existingRoot = roots.find((r) => r.name === root.name);
if (existingRoot) {
if (!areFieldsIdentical(existingRoot.fields, root.fields)) {
throw new Error(`Root ${root.name ?? 'unnamed'} already exists with different fields`);
}
return;
}
roots.push(root);
},
},
},
build: (builder) => {
// merge fragments together
for (const fragment of mergeGraphQLFragments(fragments)) {
queries.push(renderGraphQLFragment(fragment));
}
// merge roots together
for (const root of roots) {
queries.push(renderGraphQLRoot(root));
}
if (config.rowFields.length > 0) {
// create fragment and query
queries.push(renderGraphQLFragment({
name: rowFragmentName,
type: modelName,
fields: config.rowFields,
}), renderGraphQLRoot({
type: 'query',
name: listQueryName,
fields: [
{
name: listFieldName,
fields: [{ type: 'spread', on: rowFragmentName }],
},
],
}));
}
if (config.formFields.length > 0) {
queries.push(renderGraphQLFragment({
name: editFragmentName,
type: modelName,
fields: config.formFields,
}), renderGraphQLRoot({
type: 'query',
name: editQueryName,
variables: [{ name: 'id', type: 'Uuid!' }],
fields: [
{
name: editFieldName,
args: [
{
name: 'id',
value: { type: 'variable', variable: 'id' },
},
],
fields: [{ type: 'spread', on: editFragmentName }],
},
],
}));
}
if (config.generateCreate) {
queries.push(createMutation(createMutationName, createFieldName, `Create${modelName}Input`));
}
if (config.generateUpdate) {
queries.push(createMutation(updateMutationName, updateFieldName, `Update${modelName}Input`));
}
if (config.generateDelete) {
queries.push(createMutation(deleteMutationName, deleteFieldName, `Delete${modelName}Input`, true));
}
if (queries.length > 0) {
const filePath = path.join(reactRoutes.getOutputRelativePath(), 'queries.gql');
builder.writeFile({
id: `${modelId}-crud-queries`,
destination: filePath,
contents: queries.join('\n\n'),
});
}
},
};
},
}),
}),
});
//# sourceMappingURL=admin-crud-queries.generator.js.map